Revert "Unmaintained code removal - ipojo"
This reverts commit 4887e0856d789c35b82ffb69dab658963d42fe78.
diff --git a/ipojo/.gitignore b/ipojo/.gitignore
new file mode 100644
index 0000000..68cde20
--- /dev/null
+++ b/ipojo/.gitignore
@@ -0,0 +1,4 @@
+.project
+.settings
+.classpath
+target
\ No newline at end of file
diff --git a/ipojo/arch/changelog.txt b/ipojo/arch/changelog.txt
new file mode 100644
index 0000000..b180064
--- /dev/null
+++ b/ipojo/arch/changelog.txt
@@ -0,0 +1,26 @@
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+ * [FELIX-996] - Arch -factory command always prints out one component factory
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-797] - Composite Architecture contains duplicate instances
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/arch/obr.xml b/ipojo/arch/obr.xml
new file mode 100644
index 0000000..8832ddf
--- /dev/null
+++ b/ipojo/arch/obr.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<obr>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.architecture.Architecture)" multiple="true" name="service" optional="true">Import Service org.apache.felix.ipojo.architecture.Architecture</require>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.Factory)" multiple="false" name="service" optional="true">Import Service org.apache.felix.ipojo.Factory</require>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.HandlerFactory)" multiple="false" name="service" optional="true">Import Service org.apache.felix.ipojo.HandlerFactory</require>
+ <require extend="false" filter="(&(name=requires)(namespace=org.apache.felix.ipojo))" multiple="false" optional="false" name="ipojo.handler">Requires Handler</require>
+</obr>
\ No newline at end of file
diff --git a/ipojo/arch/pom.xml b/ipojo/arch/pom.xml
new file mode 100644
index 0000000..49eef09
--- /dev/null
+++ b/ipojo/arch/pom.xml
@@ -0,0 +1,118 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Arch Command</name>
+ <artifactId>org.apache.felix.ipojo.arch</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+
+ <description>Arch command to collect and print information about iPOJO instances.</description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-arch-command.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.shell</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO Arch Command</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Arch command for Felix
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-arch-command.html
+ </Bundle-DocURL>
+ <Private-Package>org.apache.felix.ipojo.arch</Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ <metadata>
+ <![CDATA[
+ <ipojo>
+ <component classname="org.apache.felix.ipojo.arch.ArchCommandImpl" public="false">
+ <Provides />
+ <requires field="m_archs" optional="true" proxy="false" />
+ <requires field="m_factories" optional="true" proxy="false" />
+ <requires field="m_handlers" optional="true" proxy="false" />
+ </component>
+ <instance component="org.apache.felix.ipojo.arch.ArchCommandImpl" name="ArchCommand" />
+ </ipojo>
+ ]]>
+ </metadata>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/arch/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/arch/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/arch/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/arch/src/main/appended-resources/META-INF/NOTICE b/ipojo/arch/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/arch/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/arch/src/main/java/org/apache/felix/ipojo/arch/ArchCommandImpl.java b/ipojo/arch/src/main/java/org/apache/felix/ipojo/arch/ArchCommandImpl.java
new file mode 100644
index 0000000..4010b7d
--- /dev/null
+++ b/ipojo/arch/src/main/java/org/apache/felix/ipojo/arch/ArchCommandImpl.java
@@ -0,0 +1,233 @@
+/*
+ * 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.arch;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.shell.Command;
+
+/**
+ * Implementation of the arch command printing the actual architecture.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ArchCommandImpl implements Command {
+
+ /** List of arch services. */
+ private Architecture[] m_archs;
+
+ /** Factory services. */
+ private Factory[] m_factories;
+
+ /** Handler Factories. */
+ private HandlerFactory[] m_handlers;
+
+ /**
+ * Get the command name.
+ * @return the command name (arch)
+ * @see org.apache.felix.shell.Command#getName()
+ */
+ public String getName() {
+ return "arch";
+ }
+
+ /**
+ * Gets help message.
+ * @return the command usage.
+ * @see org.apache.felix.shell.Command#getUsage()
+ */
+ public String getUsage() {
+ return "arch [-factories] [-instances] [-handlers] [-factory factory_name] [-instance instance_name]";
+ }
+
+ /**
+ * Gets a small description.
+ * @return get a description.
+ * @see org.apache.felix.shell.Command#getShortDescription()
+ */
+ public String getShortDescription() {
+ return "Architecture command : display the architecture";
+ }
+
+ /**
+ * Executes the arch command.
+ * @param line : command line
+ * @param out : the default output stream
+ * @param err : the error output stream
+ * @see org.apache.felix.shell.Command#execute(java.lang.String, java.io.PrintStream, java.io.PrintStream)
+ */
+ public void execute(String line, PrintStream out, PrintStream err) {
+ String line2 = line.substring("arch".length()).trim();
+
+ if (line2.equalsIgnoreCase("-instances") || line2.length() == 0) {
+ printInstances(out);
+ return;
+ }
+
+ if (line2.equalsIgnoreCase("-factories")) {
+ printFactories(out);
+ return;
+ }
+
+ if (line2.startsWith("-factory")) {
+ String name = line2.substring("-factory".length()).trim();
+ printFactory(name, out, err);
+ return;
+ }
+
+ if (line2.startsWith("-instance")) {
+ String name = line2.substring("-instance".length()).trim();
+ printInstance(name, out, err);
+ return;
+ }
+
+ if (line2.startsWith("-handlers")) {
+ printHandlers(out);
+ return;
+ }
+
+ if (line2.startsWith("-stats")) {
+ printStats(out);
+ return;
+ }
+
+ err.println(getUsage());
+ }
+
+ /**
+ * Prints the statistics.
+ * @param out the out
+ */
+ private void printStats(PrintStream out) {
+ try {
+ Field field = IPojoFactory.class.getDeclaredField("INSTANCE_NAME");
+ field.setAccessible(true); // The field is not accessible.
+ List names = (List) field.get(null);
+ out.println("Number of living instances : " + names.size());
+ out.println("Created instances : " + names);
+ } catch (SecurityException e) {
+ out.println("Cannot compute stats : " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ out.println("Cannot compute stats : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ out.println("Cannot compute stats : " + e.getMessage());
+ } catch (NoSuchFieldException e) {
+ out.println("Cannot compute stats : " + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Prints instance list.
+ * @param out : default print stream
+ */
+ private void printInstances(PrintStream out) {
+ for (int i = 0; i < m_archs.length; i++) {
+ InstanceDescription instance = m_archs[i].getInstanceDescription();
+ if (instance.getState() == ComponentInstance.VALID) {
+ out.println("Instance " + instance.getName() + " -> valid");
+ }
+ if (instance.getState() == ComponentInstance.INVALID) {
+ out.println("Instance " + instance.getName() + " -> invalid");
+ }
+ if (instance.getState() == ComponentInstance.STOPPED) {
+ out.println("Instance " + instance.getName() + " -> stopped");
+ }
+ }
+ }
+
+ /**
+ * Prints instance description.
+ * @param name : instance name
+ * @param out : default print stream
+ * @param err : error print stream (if the instance is not found)
+ */
+ private void printInstance(String name, PrintStream out, PrintStream err) {
+ for (int i = 0; i < m_archs.length; i++) {
+ InstanceDescription instance = m_archs[i].getInstanceDescription();
+ if (instance.getName().equalsIgnoreCase(name)) {
+ out.println(instance.getDescription());
+ return;
+ }
+ }
+ err.println("Instance " + name + " not found");
+ }
+
+ /**
+ * Prints factories.
+ * @param out : output stream
+ */
+ private void printFactories(PrintStream out) {
+ for (int i = 0; i < m_factories.length; i++) {
+ if (m_factories[i].getMissingHandlers().size() == 0) {
+ out.println("Factory " + m_factories[i].getName() + " (VALID)");
+ } else {
+ out.println("Factory " + m_factories[i].getName() + " (INVALID : " + m_factories[i].getMissingHandlers() + ")");
+ }
+ }
+ }
+
+ /**
+ * Prints factory description.
+ * @param name : factory name
+ * @param out : default print stream
+ * @param err : error print stream (if the factory is not found)
+ */
+ private void printFactory(String name, PrintStream out, PrintStream err) {
+ boolean found = false;
+ for (int i = 0; i < m_factories.length; i++) {
+ if (m_factories[i].getName().equalsIgnoreCase(name)) {
+ // Skip a line if already found
+ if (found) {
+ out.println();
+ }
+ out.println(m_factories[i].getDescription());
+ found = true;
+ }
+ }
+ if (! found) {
+ err.println("Factory " + name + " not found");
+ }
+ }
+
+ /**
+ * Prints the list of available handlers (and validity).
+ * @param out : default print stream
+ */
+ private void printHandlers(PrintStream out) {
+ for (int i = 0; i < m_handlers.length; i++) {
+ String name = m_handlers[i].getHandlerName();
+ if ("composite".equals(m_handlers[i].getType())) {
+ name = name + " [composite]";
+ }
+ if (m_handlers[i].getMissingHandlers().size() == 0) {
+ out.println("Handler " + name + " (VALID)");
+ } else {
+ out.println("Handler " + name + " (INVALID : " + m_handlers[i].getMissingHandlers() + ")");
+ }
+ }
+ }
+}
diff --git a/ipojo/distributions/handler-tutorial/FooService-And-Impl/pom.xml b/ipojo/distributions/handler-tutorial/FooService-And-Impl/pom.xml
new file mode 100755
index 0000000..cf0967d
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/FooService-And-Impl/pom.xml
@@ -0,0 +1,65 @@
+<!--
+ ~ 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>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+
+ <name>iPOJO Foo Service</name>
+
+ <artifactId>org.apache.felix.ipojo.log.foo</artifactId>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.felix.ipojo.foo
+ </Export-Package>
+ <Private-Package>
+ org.apache.felix.ipojo.foo.impl
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/FooService.java b/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/FooService.java
new file mode 100755
index 0000000..1bd0b9f
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/FooService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.foo;
+
+/**
+ * A service interface doing mostly nothing.
+ */
+public interface FooService {
+
+ public void foo();
+
+}
diff --git a/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/impl/FooServiceImpl.java b/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/impl/FooServiceImpl.java
new file mode 100755
index 0000000..2817fe4
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/FooService-And-Impl/src/main/java/org/apache/felix/ipojo/foo/impl/FooServiceImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.foo.impl;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.foo.FooService;
+
+
+@Component
+@Provides
+@Instantiate(name = "ipojo.foo.provider")
+/**
+ * A very simple implementation of the FooService.
+ */
+public class FooServiceImpl implements FooService {
+
+ public void foo() {
+ System.out.println("Foo");
+ }
+
+
+}
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/pom.xml b/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/pom.xml
new file mode 100755
index 0000000..bbe35d9
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/pom.xml
@@ -0,0 +1,57 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+ <name>iPOJO Log Handler Consumer</name>
+ <artifactId>org.apache.felix.ipojo.log.consumer</artifactId>
+ <description>A bundle using the log handler</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.log.foo</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.log.handler</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.log.handler.example
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/src/main/java/org/apache/felix/ipojo/log/handler/example/SimpleComponent.java b/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/src/main/java/org/apache/felix/ipojo/log/handler/example/SimpleComponent.java
new file mode 100755
index 0000000..e6c1e3e
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler-Consumer/src/main/java/org/apache/felix/ipojo/log/handler/example/SimpleComponent.java
@@ -0,0 +1,26 @@
+package org.apache.felix.ipojo.log.handler.example;
+
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.foo.FooService;
+import org.apache.felix.ipojo.log.handler.Log;
+
+@Component(immediate = true)
+@Log(level = Log.Level.INFO) // We configure the handler.
+@Instantiate(name = "my.simple.consumer")
+public class SimpleComponent {
+
+ @Requires
+ FooService fs;
+
+ @Validate
+ public void starting() {
+ System.out.println("Starting...");
+ fs.foo();
+ }
+
+ @Invalidate
+ public void stopping() {
+ System.out.println("Stopping...");
+ }
+}
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler-In-Felix/pom.xml b/ipojo/distributions/handler-tutorial/Log-Handler-In-Felix/pom.xml
new file mode 100644
index 0000000..c1a58f7
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler-In-Felix/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>loghandler-tutorial-felix</artifactId>
+ <name>Log-Handler-In-Felix</name>
+
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.log</artifactId>
+ <version>1.0.1</version>
+ </dependency>
+
+ <!-- our project -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.log.foo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.log.handler</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.log.consumer</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+
+ <execution>
+ <id>unpack-felix</id>
+ <phase>package</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>org.apache.felix.main.distribution</includeArtifactIds>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>copy-bundles</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ org.apache.felix.ipojo.log.foo,
+ org.apache.felix.ipojo.log.handler,
+ org.apache.felix.ipojo.log.consumer,
+ org.apache.felix.log,org.apache.felix.ipojo,
+ org.apache.felix.ipojo.arch.gogo
+ </includeArtifactIds>
+ <outputDirectory>${project.build.directory}/felix-framework-${felix.version}/bundle
+ </outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+
+</project>
\ No newline at end of file
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler/pom.xml b/ipojo/distributions/handler-tutorial/Log-Handler/pom.xml
new file mode 100755
index 0000000..fbf2e21
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler/pom.xml
@@ -0,0 +1,76 @@
+<!--
+ ~ 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>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+ <name>iPOJO Log Handler</name>
+ <artifactId>org.apache.felix.ipojo.log.handler</artifactId>
+ <description>A handler logging messages in an OSGi Log Service</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.log.handler
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/Log.java b/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/Log.java
new file mode 100644
index 0000000..f9aa1db
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/Log.java
@@ -0,0 +1,35 @@
+/*
+ * 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.log.handler;
+
+/**
+ * The annotation used to configure the LogHandler.
+ */
+public @interface Log {
+
+ public enum Level {
+ INFO, ERROR, WARNING
+ }
+
+ /**
+ * @return the log level
+ */
+ Level level();
+}
diff --git a/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/LogHandler.java b/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/LogHandler.java
new file mode 100755
index 0000000..9b5609b
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Log-Handler/src/main/java/org/apache/felix/ipojo/log/handler/LogHandler.java
@@ -0,0 +1,109 @@
+/*
+ * 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.log.handler;
+
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.annotations.Handler;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.service.log.LogService;
+
+import java.util.Dictionary;
+
+// Declare a handler.
+@Handler(name = "Log", namespace = LogHandler.NAMESPACE)
+public class LogHandler extends PrimitiveHandler {
+
+ public static final String NAMESPACE = "org.apache.felix.ipojo.log.handler";
+
+ // Handlers are iPOJO components, so can use service dependencies
+ @Requires(optional = true, nullable = false)
+ LogService log;
+ private InstanceManager instanceManager;
+ private int logLevel;
+
+ /**
+ * Parses the component's metadata to retrieve the log level in which we log messages.
+ *
+ * @param metadata component's metadata
+ * @param configuration instance configuration (unused in this example)
+ * @throws ConfigurationException the configuration is inconsistent
+ */
+ @Override
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ // First parse the metadata to check if the log handler logLevel
+
+ // Get all Namespace:log element from the metadata
+ Element[] log_elements = metadata.getElements("log", NAMESPACE);
+
+ // If an element match, parse the logLevel attribute of the first found element
+ if (log_elements[0].containsAttribute("level")) {
+ String l = log_elements[0].getAttribute("level");
+ if (l.equalsIgnoreCase("info")) {
+ logLevel = LogService.LOG_INFO;
+ } else if (l.equalsIgnoreCase("error")) {
+ logLevel = LogService.LOG_ERROR;
+ } else if (l.equalsIgnoreCase("warning")) {
+ logLevel = LogService.LOG_WARNING;
+ }
+ }
+
+ instanceManager = getInstanceManager();
+ }
+
+ /**
+ * The instance is starting.
+ */
+ public void start() {
+ if (log != null) {
+ log.log(logLevel, "The component instance " + instanceManager.getInstanceName() + " is starting");
+ }
+ }
+
+ /**
+ * The instance is stopping.
+ */
+ public void stop() {
+ if (log != null) {
+ log.log(logLevel, "The component instance " + instanceManager.getInstanceName() + " is stopping");
+ }
+ }
+
+ /**
+ * Logging messages when the instance state is changing
+ *
+ * @param state the new state
+ */
+ public void stateChanged(int state) {
+ if (log != null) {
+ if (state == InstanceManager.VALID) {
+ System.out.println("The component instance " + instanceManager.getInstanceName() + " becomes valid");
+ log.log(logLevel, "The component instance " + instanceManager.getInstanceName() + " becomes valid");
+ }
+ if (state == InstanceManager.INVALID) {
+ System.out.println("The component instance " + instanceManager.getInstanceName() + " becomes invalid");
+ log.log(logLevel, "The component instance " + instanceManager.getInstanceName() + " becomes invalid");
+ }
+ }
+ }
+}
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/pom.xml b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/pom.xml
new file mode 100755
index 0000000..e9094f8
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/pom.xml
@@ -0,0 +1,68 @@
+<!--
+ 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>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+ <name>iPOJO Property Handler Consumer</name>
+ <artifactId>org.apache.felix.ipojo.properties.consumer</artifactId>
+ <description>A bundle using the properties handler</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.properties.handler</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.handler.props.example
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/ipojo/metadata.xml b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/ipojo/metadata.xml
new file mode 100755
index 0000000..29f7aa1
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/ipojo/metadata.xml
@@ -0,0 +1,9 @@
+<ipojo>
+ <!-- Declare an instance illustrating instance configuration -->
+ <instance component="PropertiesTester"
+ name="instance-using-properties-i1">
+ <property name="props.file"
+ value="props\properties-i1.properties" />
+ </instance>
+
+</ipojo>
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.java b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.java
new file mode 100755
index 0000000..e75aa2d
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-Consumer/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.java
@@ -0,0 +1,78 @@
+/*
+ * 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.handler.properties.example;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Invalidate;
+import org.apache.felix.ipojo.annotations.Validate;
+import org.apache.felix.ipojo.handler.properties.Properties;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+@Component(immediate = true, name = "PropertiesTester")
+@Properties(file = "props/my-properties.properties")
+@Instantiate
+public class PropertiesTester {
+
+ // These two fields will be injected.
+ private String property1;
+ private String property2;
+
+ /**
+ * Starting method.
+ * This method will be called when the instance starts.
+ */
+ @Validate
+ public void start() {
+ System.out.println("PropertiesTester is starting ...");
+ // Read the injected properties.
+ System.out.println("Property 1 : " + property1);
+ System.out.println("Property 2 : " + property2);
+
+ // Update the properties.
+ updateProperties();
+ }
+
+ /**
+ * Stopping method.
+ * This method will be called when the instance stops.
+ */
+ @Invalidate
+ public void stop() {
+ System.out.println("PropertiesTester is stopping ...");
+ System.out.println("Property 1 : " + property1);
+ System.out.println("Property 2 : " + property2);
+ }
+
+ /**
+ * This method just updates managed properties.
+ * It appends the current date to the actual property value.
+ */
+ private void updateProperties() {
+ System.out.println("Update properties");
+ Date date = new Date();
+ DateFormat df = DateFormat.getDateTimeInstance();
+ // The properties will be updated in the property file
+ property1 = property1 + " - " + df.format(date);
+ property2 = property2 + " - " + df.format(date);
+ }
+
+}
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/pom.xml b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/pom.xml
new file mode 100644
index 0000000..a646b6b
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>Property-Handler-In-Felix</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <!-- our project -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.properties.handler</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.properties.consumer</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+
+ <execution>
+ <id>unpack-felix</id>
+ <phase>package</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>org.apache.felix.main.distribution</includeArtifactIds>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>copy-bundles</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ org.apache.felix.ipojo.properties.handler,
+ org.apache.felix.ipojo.properties.consumer,
+ org.apache.felix.ipojo,
+ org.apache.felix.ipojo.arch.gogo
+ </includeArtifactIds>
+ <outputDirectory>${project.build.directory}/felix-framework-${felix.version}/bundle
+ </outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--
+ we also copy properties file to the distribution folder,
+ the properties are stored in src/main/resources/props
+ -->
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>
+ ${project.build.directory}/felix-framework-${felix.version}/props
+ </outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/resources/props</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/my-properties.properties b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/my-properties.properties
new file mode 100644
index 0000000..8ebd943
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/my-properties.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+property1:"aaa"
+property2:"bbb"
\ No newline at end of file
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/properties-i1.properties b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/properties-i1.properties
new file mode 100644
index 0000000..195278e
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler-In-Felix/src/main/resources/props/properties-i1.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+property1:"ccc"
+property2:"ddd"
\ No newline at end of file
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler/pom.xml b/ipojo/distributions/handler-tutorial/Property-Handler/pom.xml
new file mode 100755
index 0000000..4261fcb
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler/pom.xml
@@ -0,0 +1,61 @@
+<!--
+ ~ 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>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+ <name>iPOJO Properties Handler</name>
+ <artifactId>org.apache.felix.ipojo.properties.handler</artifactId>
+ <description>A handler loading a property file</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.handler.properties
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/Properties.java b/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/Properties.java
new file mode 100755
index 0000000..8a0f49b
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/Properties.java
@@ -0,0 +1,33 @@
+/*
+ * 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.handler.properties;
+
+/**
+ * The Properties annotation.
+ * This annotation may be used in POJO class to used the Property handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public @interface Properties {
+
+ /**
+ * Returns the property file used by the handler.
+ */
+ String file();
+
+}
diff --git a/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.java b/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.java
new file mode 100755
index 0000000..08efa3c
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/Property-Handler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.java
@@ -0,0 +1,295 @@
+/*
+ * 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.handler.properties;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.annotations.Handler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+
+/**
+ * This handler load a properties file containing property value.
+ * The handler injects this values inside fields. When stopped the handler stores updated value inside the file. The
+ * properties file contains <pre>field-name : field-value</pre> (field-value are strings)
+ *
+ * Instances can override file locations by setting the {@literal properties.file} property.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Handler(name="properties", namespace = PropertiesHandler.NAMESPACE)
+public class PropertiesHandler extends PrimitiveHandler {
+
+ /**
+ * The Handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.handler.properties";
+
+ /**
+ * The loaded properties.
+ */
+ private Properties m_properties = new Properties();
+
+ /**
+ * The properties file location, configured in the component's metadata.
+ */
+ private String m_file;
+
+ /**
+ * This method is the first to be invoked.
+ * This method aims to configure the handler. It receives the component type metadata and the instance
+ * configuration. The method parses given metadata and registers fields to inject.
+ *
+ * Step 3 : when the instance configuration contains the properties.file property, it overrides the properties file location.
+ *
+ * @param metadata : component type metadata
+ * @param configuration : instance description
+ * @throws ConfigurationException : the configuration of the handler has failed.
+ */
+ @SuppressWarnings("unchecked")
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ // Parse metadata to get <properties file="$file"/>
+
+ // Get all elements to configure the handler
+ Element[] elem = metadata.getElements("properties", NAMESPACE);
+
+ switch (elem.length) {
+ case 0:
+ // No matching element in metadata, throw a configuration error.
+ // It actually happen only if you force the handler to be plugged.
+ throw new ConfigurationException("No properties found");
+ case 1:
+ // One 'properties' found, get attributes.
+ m_file = elem[0].getAttribute("file");
+ if (m_file == null) {
+ // if file is null, throw a configuration error.
+ throw new ConfigurationException("Malformed properties element : file attribute must be set");
+ }
+ break;
+ default:
+ // To simplify we handle only one properties element.
+ throw new ConfigurationException("Only one properties element is supported");
+ }
+
+ // Look if the instance overrides file location :
+ String instanceFile = (String) configuration.get("properties.file");
+ if (instanceFile != null) {
+ m_file = instanceFile;
+ }
+
+ // Load properties
+ try {
+ loadProperties();
+ } catch (IOException e) {
+ throw new ConfigurationException("Error when reading the " + m_file + " file : " + e.getMessage());
+ }
+
+ // Register fields
+ // By convention, properties file entry are field name, so look for each property to get field list.
+
+ //First get Pojo Metadata metadata :
+ PojoMetadata pojoMeta = getPojoMetadata();
+ Enumeration e = m_properties.keys();
+ while (e.hasMoreElements()) {
+ String field = (String) e.nextElement();
+ FieldMetadata fm = pojoMeta.getField(field);
+
+ if (fm == null) { // The field does not exist
+ throw new ConfigurationException("The field " + field + " is declared in the properties file but does not exist in the pojo");
+ }
+
+ // Then check that the field is a String field
+ if (!fm.getFieldType().equals(String.class.getName())) {
+ throw new ConfigurationException("The field " + field + " exists in the pojo, but is not a String");
+ }
+
+ // All checks are ok, register the interceptor.
+ getInstanceManager().register(fm, this);
+ }
+
+ // Finally register the field to listen
+ }
+
+ /**
+ * This method is called when the instance start (after the configure method). We just print stored properties.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // The properties are already loaded (in the configure method), just print values.
+ m_properties.list(System.out);
+ }
+
+ /**
+ * This method is called when the instance stops. We save the properties to not lost the instance state and clear the stored properties.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ try {
+ saveProperties();
+ } catch (IOException e) {
+ error("Cannot read the file : " + m_file, e); // Log an error message by using the iPOJO logger
+ }
+ m_properties = null;
+ }
+
+ /**
+ * This method is called at each time the pojo 'get' a listened field. The method return the stored value.
+ * @param pojo : pojo object getting the field
+ * @param field : field name.
+ * @param o : previous value.
+ * @return the stored value.
+ */
+ public Object onGet(Object pojo, String field, Object o) {
+ // When the pojo requires a value for a managed field, this method is invoked.
+ // So, we have just to return the stored value.
+ return m_properties.get(field);
+ }
+
+ /**
+ * This method is called at each time the pojo 'set' a listened field. This method updates the local properties.
+ * @param pojo : pojo object setting the field
+ * @param field : field name
+ * @param newvalue : new value
+ */
+ public void onSet(Object pojo, String field, Object newvalue) {
+ // When the pojo set a value to a managed field, this method is invoked.
+ // So, we update the stored value.
+ m_properties.put(field, newvalue);
+ }
+
+ /**
+ * Step 2 : state properties when the instance becomes invalid.
+ * @param newState : the instance state
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int newState) {
+ // This method is invoked each times that the instance state changed.
+
+ // If the new state is invalid, save the properties.
+ if (newState == ComponentInstance.INVALID) {
+ // Reload properties
+ try {
+ saveProperties();
+ } catch (IOException e) {
+ error("Cannot read the file : " + m_file, e); // Log an error message by using the iPOJO logger
+ }
+ }
+ }
+
+ /**
+ * Step 5 : dynamic reconfiguration. This method is call when the instance is reconfigured externally. The given property contains property value.
+ * @param dict : new properties
+ * @see org.apache.felix.ipojo.Handler#reconfigure(java.util.Dictionary)
+ */
+ @SuppressWarnings("unchecked")
+ public synchronized void reconfigure(Dictionary dict) {
+ // For each property, look if a new value is contained in the new configuration.
+ Enumeration e = m_properties.keys();
+ while (e.hasMoreElements()) {
+ String field = (String) e.nextElement();
+ String value = (String) dict.get(field);
+ // If the dictionary contains a value, update the stored value.
+ if (value != null) {
+ m_properties.put(field, value);
+ }
+ }
+ }
+
+ /**
+ * Returns handler description.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return new Description(this);
+ }
+
+ /**
+ * Helper method just loading the properties.
+ * @throws IOException : the file cannot be read.
+ */
+ private void loadProperties() throws IOException {
+ // Load the properties file from file system
+ File file = new File(m_file);
+ InputStream is = new FileInputStream(file);
+ m_properties.load(is);
+ }
+
+ /**
+ * Helper method writing properties.
+ * @throws IOException : the file cannot be written.
+ */
+ private void saveProperties() throws IOException {
+ // Store the file, modified the last modification date.
+ File file = new File(m_file);
+ OutputStream os = new FileOutputStream(file);
+ m_properties.store(os, "");
+ }
+
+ /**
+ * Step 3 : The handler will participate to the instance architecture.
+ * This class describing the handler.
+ */
+ private class Description extends HandlerDescription {
+
+ /**
+ * Instantiates a new description.
+ * @param h the h
+ */
+ public Description(PrimitiveHandler h) {
+ super(h);
+ }
+
+ /**
+ * This method must return the Element describing the handler. The description of this handler contains the list of properties with attached
+ * value.
+ * @return the description of the handler.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ @SuppressWarnings("unchecked")
+ public Element getHandlerInfo() {
+ Element elem = super.getHandlerInfo(); // This method must be called to get the root description element.
+ Enumeration e = m_properties.keys();
+ while (e.hasMoreElements()) {
+ String field = (String) e.nextElement();
+ Element prop = new Element("property", ""); // Create an element for the actual property.
+ // Add two attribute (the field and the value).
+ prop.addAttribute(new Attribute("field", field));
+ prop.addAttribute(new Attribute("value", (String) m_properties.get(field)));
+ elem.addElement(prop); // Attach the current element to the root element.
+ }
+ return elem;
+ }
+
+ }
+}
diff --git a/ipojo/distributions/handler-tutorial/pom.xml b/ipojo/distributions/handler-tutorial/pom.xml
new file mode 100644
index 0000000..6454332
--- /dev/null
+++ b/ipojo/distributions/handler-tutorial/pom.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-handler-tutorial</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+
+ <packaging>pom</packaging>
+
+ <description>
+ Build the handlers form the tutorial and distributions to test them
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.main.distribution</artifactId>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ </dependency>
+ </dependencies>
+
+ <modules>
+ <!-- Log Handler tutorial -->
+ <module>FooService-And-Impl</module>
+ <module>Log-Handler</module>
+ <module>Log-Handler-Consumer</module>
+ <module>Log-Handler-In-Felix</module>
+
+ <!-- Property handler tutorial -->
+ <module>Property-Handler</module>
+ <module>Property-Handler-Consumer</module>
+ <module>Property-Handler-In-Felix</module>
+ </modules>
+
+ <properties>
+ <felix.version>4.2.1</felix.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.main.distribution</artifactId>
+ <version>4.2.1</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.6</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptorRefs>
+ <ref>project</ref>
+ </descriptorRefs>
+ <attach>true</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/distributions/ipojo-webconsole-quicktart/pom.xml b/ipojo/distributions/ipojo-webconsole-quicktart/pom.xml
new file mode 100644
index 0000000..7b84c5b
--- /dev/null
+++ b/ipojo/distributions/ipojo-webconsole-quicktart/pom.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.distributions</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ipojo-webconsole-quicktart</artifactId>
+
+ <packaging>pom</packaging>
+
+ <description>
+ Build a distribution of Felix including iPOJO, and a working web console
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.main.distribution</artifactId>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.webconsole</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <version>4.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole.plugins.packageadmin</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole.plugins.memoryusage</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.http.jetty</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>com.springsource.javax.servlet</artifactId>
+ <version>2.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ <version>1.4</version>
+ </dependency>
+ </dependencies>
+
+ <!-- Add OW2 repository -->
+ <repositories>
+ <repository>
+ <id>ow2.releases</id>
+ <url>http://repository.ow2.org/nexus/content/groups/public/</url>
+ </repository>
+
+ <repository>
+ <id>com.springsource.repository.libraries.external</id>
+ <name>SpringSource Enterprise Bundle Repository - External Library Releases</name>
+ <url>http://repository.springsource.com/maven/bundles/external</url>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/distribution.xml</descriptor>
+ </descriptors>
+ <attach>true</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/distributions/ipojo-webconsole-quicktart/src/main/assembly/distribution.xml b/ipojo/distributions/ipojo-webconsole-quicktart/src/main/assembly/distribution.xml
new file mode 100644
index 0000000..20e8bf1
--- /dev/null
+++ b/ipojo/distributions/ipojo-webconsole-quicktart/src/main/assembly/distribution.xml
@@ -0,0 +1,59 @@
+<!--
+ ~ 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>distribution</id>
+
+ <formats>
+ <format>zip</format>
+ <format>tar.gz</format>
+ </formats>
+
+ <dependencySets>
+ <!-- unpack Felix distribution -->
+ <dependencySet>
+ <includes>
+ <include>*:org.apache.felix.main.distribution:*</include>
+ </includes>
+ <unpack>true</unpack>
+ <outputDirectory>.</outputDirectory>
+ <unpackOptions>
+ <excludes>
+ <exclude>**/doc/**</exclude>
+ </excludes>
+ </unpackOptions>
+ </dependencySet>
+
+ <dependencySet>
+ <includes>
+ <include>*:org.apache.felix.*:jar</include>
+ <include>javax.servlet:com.springsource.javax.servlet:*</include>
+ <include>org.osgi:org.osgi.compendium:*</include>
+ <include>org.json:org.ow2.chameleon.commons.json:*</include>
+ <include>commons-io:commons-io:*</include>
+ <include>commons-fileupload:*:*</include>
+ </includes>
+ <unpack>false</unpack>
+ <outputDirectory>./felix-framework-${felix.version}/bundle</outputDirectory>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
\ No newline at end of file
diff --git a/ipojo/distributions/pom.xml b/ipojo/distributions/pom.xml
new file mode 100644
index 0000000..d331399
--- /dev/null
+++ b/ipojo/distributions/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.distributions</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+
+ <packaging>pom</packaging>
+
+ <description>
+ This project build distributions for the web site, it does not intend to be released, just built.
+ </description>
+
+ <modules>
+ <module>ipojo-webconsole-quicktart</module>
+ <module>handler-tutorial</module>
+ </modules>
+
+ <properties>
+ <felix.version>4.2.1</felix.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.main.distribution</artifactId>
+ <version>4.2.1</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.10.0</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/changelog.txt b/ipojo/handler/eventadmin/changelog.txt
new file mode 100644
index 0000000..dec3825
--- /dev/null
+++ b/ipojo/handler/eventadmin/changelog.txt
@@ -0,0 +1,32 @@
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2718] - EventHandler are invoked one by one when using the @Subscribe handler
+
+** Improvement
+ * [FELIX-2631] - Rename @Publisher and @Subscriber attributes to follow the java naming conventions
+ * [FELIX-2634] - Rename the @Publisher annotation into @Publishes annotation to avoid collision
+ * [FELIX-2711] - The event admin handler should provides a Handler Description
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1938] - Bad error message when an Event Subscriber does not set the data type and data key
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+
+ Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-794] - Event Admin handler reject correctly formed topics
+
+** Improvement
+ * [FELIX-795] - Improve metadata and manipulator performance
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+Version 1.0.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/pom.xml b/ipojo/handler/eventadmin/eventadmin-handler-it/pom.xml
new file mode 100644
index 0000000..20f637e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/pom.xml
@@ -0,0 +1,378 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
+ <name>Apache Felix iPOJO Event Admin Handler - Integration Test</name>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin-it</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.1</url.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin</artifactId>
+ <version>${project.version}</version>
+ <!--
+ The event admin handler depends on an older version of the compendium and core, to avoid issue during
+ tests, we must exclude those artifacts and trust the framework to provide the right / compatible
+ version
+ -->
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>regular</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/regular</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>test-all</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>equinox-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>equinox</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/equinox-native</cloneProjectsTo>
+
+ </configuration>
+ </execution>
+ <execution>
+ <id>felix-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/felix-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+</project>
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml
new file mode 100644
index 0000000..c5ef57b
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin-it</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-event-admin-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java
new file mode 100644
index 0000000..d6ea1ef
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of an event vendor that directly uses the Event Admin service
+ * to post (asynchronously) raw events.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AsyncEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The Event Admin service reference.
+ */
+ private EventAdmin m_ea;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public AsyncEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ rawEvent.put("food", donut);
+ m_ea.postEvent(new Event("food/donuts", rawEvent));
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java
new file mode 100644
index 0000000..5c0e4f3
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java
@@ -0,0 +1,100 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+/**
+ * Donut representation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Donut {
+
+ /**
+ * All possible donut flavours.
+ */
+ public static final String[] FLAVOURS = { "unflavoured", "icing sugar",
+ "chocolate", "toffee", "strawberry", "apple" };
+
+ /**
+ * The vendor's unique donut identifier.
+ */
+ private final long m_id;
+
+ /**
+ * The name of this donut's vendor.
+ */
+ private final String m_vendorName;
+
+ /**
+ * The m_flavour of this donut.
+ */
+ private final String m_flavour;
+
+ /**
+ * Create a new donut.
+ *
+ * @param id
+ * the vendor's unique donut identifier
+ * @param vendorName
+ * the name of this donut's vendor
+ * @param flavour
+ * the m_flavour of this donut
+ */
+ public Donut(long id, String vendorName, String flavour) {
+ this.m_id = id;
+ this.m_vendorName = vendorName;
+ this.m_flavour = flavour;
+ }
+
+ /**
+ * Get the vendor's unique identifier of this donut.
+ *
+ * @return the id
+ */
+ public long getId() {
+ return m_id;
+ }
+
+ /**
+ * Get the vendor name of this donut.
+ *
+ * @return the name
+ */
+ public String getVendorName() {
+ return m_vendorName;
+ }
+
+ /**
+ * Get the flavour of this donut.
+ *
+ * @return the flavour
+ */
+ public String getFlavour() {
+ return m_flavour;
+ }
+
+ /**
+ * Return the string representation of this donut.
+ *
+ * @return this donut as a String
+ */
+ public String toString() {
+ return m_id + " " + m_flavour + " (" + m_vendorName + ")";
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java
new file mode 100644
index 0000000..c13d87b
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java
@@ -0,0 +1,81 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+/**
+ * Specification of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface DonutConsumer {
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut
+ * the received donut
+ */
+ void receiveDonut(Donut donut);
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event
+ * the received event
+ */
+ void receiveEvent(Event event);
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ void clearDonuts();
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ Donut getDonut();
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ Donut[] getAllDonuts();
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ Donut waitForDonut();
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ int getNumberOfDonuts();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java
new file mode 100644
index 0000000..956b6db
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java
@@ -0,0 +1,194 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see Homer Simpson
+ */
+public class DonutConsumerImpl implements DonutConsumer {
+
+
+ /**
+ * The time that is normally necessary to cause a blacklist from the event
+ * admin service.
+ */
+ public static final long BLACK_LIST_TIME = 5000L;
+ /**
+ * The name of the donut consumer.
+ */
+ private String m_name;
+ /**
+ * The list of eaten donuts.
+ */
+ private List m_donuts = new ArrayList();
+ /**
+ * Is this consumer a slow eater ?
+ */
+ private boolean m_isSlow;
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Process incoming donuts. This method is called by the receiveDonut
+ * callback.
+ *
+ * @param donut the received donut
+ */
+ private void doReceiveDonut(Donut donut) {
+ synchronized (m_donuts) {
+ m_donuts.add(donut);
+ m_donuts.notify();
+ }
+ }
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut the received donut
+ */
+ public void receiveDonut(Donut donut) {
+ final Donut myDonut = donut;
+ if (m_isSlow) {
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(BLACK_LIST_TIME);
+ doReceiveDonut(myDonut);
+ }
+ }, m_name + " eating " + donut).start();
+ } else {
+ doReceiveDonut(donut);
+ }
+ }
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event the received event
+ */
+ public void receiveEvent(Event event) {
+ Object thing = event.getProperty("food");
+ if (Donut.class.isInstance(thing)) {
+ receiveDonut((Donut) thing);
+ } else {
+ // Nothing.
+ }
+ }
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ public void clearDonuts() {
+ synchronized (m_donuts) {
+ m_donuts.clear();
+ }
+ }
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ public Donut getDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ if (!m_donuts.isEmpty()) {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ public Donut[] getAllDonuts() {
+ Donut[] donuts = new Donut[0];
+ synchronized (m_donuts) {
+ donuts = (Donut[]) m_donuts.toArray(donuts);
+ m_donuts.clear();
+ }
+ return donuts;
+ }
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ public Donut waitForDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ while (donut == null) {
+ if (m_donuts.isEmpty()) {
+ try {
+ m_donuts.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ public int getNumberOfDonuts() {
+ int length;
+ synchronized (m_donuts) {
+ length = m_donuts.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java
new file mode 100644
index 0000000..612b72a
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.apache.felix.ipojo.handlers.event.publisher.Publisher;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of a donut vendor that send raw events instead of sending
+ * Donut objects.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DonutEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The event publisher of the donut vendor.
+ */
+ private Publisher m_publisher;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public DonutEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ String flavour = Donut.FLAVOURS[m_random.nextInt(Donut.FLAVOURS.length)];
+ Donut donut = new Donut(m_serial++, m_name, flavour);
+ rawEvent.put("food", donut);
+ rawEvent.put("flavour", flavour);
+ m_publisher.send(rawEvent);
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java
new file mode 100644
index 0000000..a098ee7
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java
@@ -0,0 +1,35 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+/**
+ * Specification of a donut vendor.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public interface DonutProvider {
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ Donut sellDonut();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java
new file mode 100644
index 0000000..2f708ba
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java
@@ -0,0 +1,76 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.apache.felix.ipojo.handlers.event.publisher.Publisher;
+
+import java.util.Random;
+
+/**
+ * The standard implementation of a donut vendor.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class DonutProviderImpl implements DonutProvider {
+
+
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+
+ /**
+ * The donut publisher of the vendor.
+ */
+ private Publisher m_publisher;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public DonutProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ m_publisher.sendData(donut);
+ System.err.println("[" + this.getClass().getSimpleName() + ":"
+ + m_name + "] Selling donut " + donut);
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java
new file mode 100644
index 0000000..4b6ba7f
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java
@@ -0,0 +1,199 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see Homer Simpson
+ */
+public class EventConsumerImpl implements DonutConsumer, EventHandler {
+
+ /**
+ * The name of the donut consumer.
+ */
+ private String m_name;
+ /**
+ * The list of eaten donuts.
+ */
+ private List m_donuts = new ArrayList();
+ /**
+ * Is this consumer a slow eater ?
+ */
+ private boolean m_isSlow;
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Process incoming donuts. This method is called by the receiveDonut
+ * callback.
+ *
+ * @param donut the received donut
+ */
+ private void doReceiveDonut(Donut donut) {
+ synchronized (m_donuts) {
+ m_donuts.add(donut);
+ m_donuts.notify();
+ }
+ }
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut the received donut
+ */
+ public void receiveDonut(Donut donut) {
+ final Donut myDonut = donut;
+ if (m_isSlow) {
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(DonutConsumerImpl.BLACK_LIST_TIME);
+ doReceiveDonut(myDonut);
+ }
+ }, m_name + " eating " + donut).start();
+ } else {
+ doReceiveDonut(donut);
+ }
+ }
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event the received event
+ */
+ public void receiveEvent(Event event) {
+ Object thing = event.getProperty("food");
+ if (Donut.class.isInstance(thing)) {
+ receiveDonut((Donut) thing);
+ } else {
+ // Nothing to do.
+ }
+ }
+
+ /**
+ * Event receiver callback. This method is called by the event admin service
+ * when a event is received.
+ *
+ * @param event the received event
+ */
+ public void handleEvent(Event event) {
+ receiveEvent(event);
+ }
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ public void clearDonuts() {
+ synchronized (m_donuts) {
+ m_donuts.clear();
+ }
+ }
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ public Donut getDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ if (!m_donuts.isEmpty()) {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ public Donut[] getAllDonuts() {
+ Donut[] donuts = new Donut[0];
+ synchronized (m_donuts) {
+ donuts = (Donut[]) m_donuts.toArray(donuts);
+ m_donuts.clear();
+ }
+ return donuts;
+ }
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ public Donut waitForDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ while (donut == null) {
+ if (m_donuts.isEmpty()) {
+ try {
+ m_donuts.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ public int getNumberOfDonuts() {
+ int length;
+ synchronized (m_donuts) {
+ length = m_donuts.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java
new file mode 100644
index 0000000..b61b530
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java
@@ -0,0 +1,63 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+/**
+ * Specification of an event tracker.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface EventTracker {
+
+ /**
+ * Clear the received events list. (Useful before tests)
+ */
+ void clearEvents();
+
+ /**
+ * Get the first received event and remove it from the events list.
+ *
+ * @return the first received event or null if no event is available
+ */
+ Event getEvent();
+
+ /**
+ * Get the whole list of received events.
+ *
+ * @return the array containing all received events
+ */
+ Event[] getAllEvents();
+
+ /**
+ * Get the first event if available or wait for an incoming event. The
+ * returned event is removed from the eaten event list.
+ *
+ * @return the first available event.
+ */
+ Event waitForEvent();
+
+ /**
+ * Return the size of the events list.
+ *
+ * @return the size of the events list
+ */
+ int getNumberOfEvents();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java
new file mode 100644
index 0000000..64f08b4
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java
@@ -0,0 +1,152 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of an event tracker.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventTrackerImpl implements EventTracker, EventHandler {
+
+ /**
+ * The name of the event tracker.
+ */
+ private String m_name;
+ /**
+ * The list of received events
+ */
+ private List m_events = new ArrayList();
+
+ /**
+ * Return the string representation of a given event.
+ *
+ * @return the string representation of a given event
+ */
+ public static String eventToString(Event e) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("[" + e.getTopic() + "] {");
+
+ String[] properties = e.getPropertyNames();
+ int n = properties.length - 1;
+ for (int i = 0; i <= n; i++) {
+ String name = properties[i];
+ buf.append(name + "=" + e.getProperty(name));
+ if (i != n)
+ buf.append(", ");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * Event receiver callback. This method is called by the event admin service
+ * when a event is received.
+ *
+ * @param event the received event
+ */
+ public void handleEvent(Event event) {
+ synchronized (m_events) {
+ m_events.add(event);
+ m_events.notify();
+ }
+ }
+
+ /**
+ * Clear the received events list. (Useful before tests)
+ */
+ public void clearEvents() {
+ synchronized (m_events) {
+ m_events.clear();
+ }
+ }
+
+ /**
+ * Get the first received event and remove it from the events list.
+ *
+ * @return the first received event or null if no event is available
+ */
+ public Event getEvent() {
+ Event event = null;
+ synchronized (m_events) {
+ if (!m_events.isEmpty()) {
+ event = (Event) m_events.remove(0);
+ }
+ }
+ return event;
+ }
+
+ /**
+ * Get the whole list of received events.
+ *
+ * @return the array containing all received events
+ */
+ public Event[] getAllEvents() {
+ Event[] events = new Event[0];
+ synchronized (m_events) {
+ events = (Event[]) m_events.toArray(events);
+ m_events.clear();
+ }
+ return events;
+ }
+
+ /**
+ * Get the first event if available or wait for an incoming event. The
+ * returned event is removed from the eaten event list.
+ *
+ * @return the first available event.
+ */
+ public Event waitForEvent() {
+ Event event = null;
+ synchronized (m_events) {
+ while (event == null) {
+ if (m_events.isEmpty()) {
+ try {
+ m_events.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ event = (Event) m_events.remove(0);
+ }
+ }
+ }
+ return event;
+ }
+
+ /**
+ * Return the size of the events list.
+ *
+ * @return the size of the events list
+ */
+ public int getNumberOfEvents() {
+ int length;
+ synchronized (m_events) {
+ length = m_events.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java
new file mode 100644
index 0000000..bf519ae
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of an event vendor that directly uses the Event Admin service
+ * to send (synchronously) raw events.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SyncEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The Event Admin service reference.
+ */
+ private EventAdmin m_ea;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public SyncEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ rawEvent.put("food", donut);
+ m_ea.sendEvent(new Event("food/donuts", rawEvent));
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml
new file mode 100644
index 0000000..fb8639e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:ev="org.apache.felix.ipojo.handlers.event">
+
+ <!-- The (asynchronous) donut provider -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="donut-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Donut publisher -->
+ <ev:publisher name="donut-publisher" field="m_publisher"
+ topics="food/donuts" data-key="food" synchronous="false"/>
+ </component>
+
+ <!-- The (asynchronous) donut provider using publishes -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="donut-provider-publishes">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Donut publisher -->
+ <ev:publishes name="donut-publisher" field="m_publisher"
+ topics="food/donuts" dataKey="food" synchronous="false"/>
+ </component>
+
+ <!-- The synchronous donut provider -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="synchronous-donut-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Donut publisher -->
+ <ev:publisher name="donut-publisher" field="m_publisher"
+ topics="food/donuts" data-key="food" synchronous="true"/>
+ </component>
+
+ <!-- The synchronous donut provider using dataKey -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="synchronous-donut-provider-2">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Donut publisher -->
+ <ev:publisher name="donut-publisher" field="m_publisher"
+ topics="food/donuts" dataKey="food" synchronous="true"/>
+ </component>
+
+ <!-- The (asynchronous) donut event provider -->
+ <component
+ classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutEventProviderImpl"
+ name="donut-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Raw events publisher -->
+ <ev:publisher name="event-publisher" field="m_publisher"
+ topics="food/donuts" synchronous="false"/>
+ </component>
+
+ <!-- The synchronous donut event provider -->
+ <component
+ classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutEventProviderImpl"
+ name="synchronous-donut-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Raw events publisher -->
+ <ev:publisher name="event-publisher" field="m_publisher"
+ topics="food/donuts" synchronous="true"/>
+ </component>
+
+ <!-- The (asynchronous) event provider -->
+ <component
+ classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.AsyncEventProviderImpl"
+ name="event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Direcly interacts with the Event Admin service -->
+ <requires field="m_ea"/>
+ </component>
+
+ <!-- The synchronous event provider -->
+ <component
+ classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.SyncEventProviderImpl"
+ name="synchronous-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Direcly interacts with the Event Admin service -->
+ <requires field="m_ea"/>
+ </component>
+
+ <!-- The donut consumer -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer">
+ <property name="name" field="m_name" value="Unknown donut consumer"/>
+ <property name="slow" field="m_isSlow" value="false"/>
+ </provides>
+ <!-- Donut events subscriber -->
+ <ev:subscriber name="donut-subscriber" callback="receiveDonut"
+ topics="food/donuts" data-key="food"
+ data-type="org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut"/>
+ </component>
+
+ <!-- The donut consumer using dataKey and dataType -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-consumer-2">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer">
+ <property name="name" field="m_name" value="Unknown donut consumer"/>
+ <property name="slow" field="m_isSlow" value="false"/>
+ </provides>
+ <!-- Donut events subscriber -->
+ <ev:subscriber name="donut-subscriber" callback="receiveDonut"
+ topics="food/donuts" dataKey="food"
+ dataType="org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut"/>
+ </component>
+
+
+ <!-- The donut event consumer -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-event-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer">
+ <property name="name" field="m_name" value="Unknown donut consumer"/>
+ <property name="slow" field="m_isSlow" value="false"/>
+ </provides>
+ <!-- Raw events subscriber -->
+ <ev:subscriber name="donut-event-subscriber" callback="receiveEvent"
+ topics="food/donuts"/>
+ </component>
+
+ <!-- The event consumer -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.EventConsumerImpl"
+ name="event-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides
+ specifications="{org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer,org.osgi.service.event.EventHandler}">
+ <property name="name" field="m_name" value="Unknown event consumer"/>
+ <property name="slow" field="m_isSlow" value="false"/>
+ <property name="event.topics" type="String" value="food/donuts"/>
+ </provides>
+ </component>
+
+ <!-- The event tracker -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTrackerImpl"
+ name="event-tracker">
+ <!-- Expose the donut consumer service -->
+ <provides
+ specifications="{org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker,org.osgi.service.event.EventHandler}">
+ <property name="name" field="m_name" value="Unknown event tracker"/>
+ <property name="event.topics" type="String" value="food/donuts"/>
+ </provides>
+ </component>
+
+
+ <!-- Example instances -->
+ <instance component="donut-provider" name="zeifhgbzre">
+ <property name="name" value="Zeifhgbzre donuts"/>
+ </instance>
+ <instance component="donut-consumer" name="zeifhgbzre simpson">
+ <property name="name" value="Zeifhgbzre simpson"/>
+ <property name="slow" value="false"/>
+ </instance>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java
new file mode 100644
index 0000000..cb93526
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java
@@ -0,0 +1,76 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.junit.After;
+import org.junit.Before;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ eventadmin()
+ };
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.3.0"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin").versionAsInProject());
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.handler.eventadmin.test.donut");
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java
new file mode 100644
index 0000000..d5eb991
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java
@@ -0,0 +1,226 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.osgi.framework.BundleContext;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+
+/**
+ * Useful variables used for the tests of the Event Admin Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EahTestUtils {
+
+ /**
+ * Enable debug messages ?
+ */
+ public static final boolean TRACE = false;
+ /**
+ * The number of tests to execute.
+ */
+ public static final int NUMBER_OF_TESTS = 50;
+ /**
+ * The time that is normally necessary to cause a blacklist from the event
+ * admin service.
+ */
+ public static final long BLACK_LIST_TIME = 5000L;
+ /**
+ * The long amount of time.
+ */
+ public static final long A_LONG_TIME = 1000L;
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+ /**
+ * The iPOJO Helper.
+ */
+ private IPOJOHelper m_ipojoHelper;
+
+ /**
+ * Construct a new Event Admin Handler Tests utility instance.
+ */
+ public EahTestUtils(BundleContext context, IPOJOHelper ipojoHelper) {
+ m_ipojoHelper = ipojoHelper;
+ m_context = context;
+ }
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ if (TRACE) {
+ System.err.println("Sleeping for " + millis + "ms");
+ }
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Return the index of the given donut flavour in the flavour array.
+ *
+ * @return the index of the given flavour or -1 if not found
+ */
+ public static int flavourIndex(String flavour) {
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ if (Donut.FLAVOURS[i].equals(flavour))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the (asynchronous) donut provider factory.
+ *
+ * @return the (asynchronous) donut provider factory
+ */
+ public Factory getDonutProviderFactory() {
+ return m_ipojoHelper.getFactory("donut-provider");
+ }
+
+ /**
+ * Return the (asynchronous) donut provider using publishes factory.
+ *
+ * @return the (asynchronous) donut provider using publishes factory
+ */
+ public Factory getDonutProviderUsingPublishesFactory() {
+ return m_ipojoHelper.getFactory("donut-provider-publishes");
+ }
+
+ /**
+ * Return the synchronous donut provider factory.
+ *
+ * @return the synchronous donut provider factory
+ */
+ public Factory getSynchronousDonutProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-provider");
+ }
+
+ /**
+ * Return the synchronous donut provider factory using
+ * dataKey
+ *
+ * @return the synchronous donut provider factory
+ */
+ public Factory getSynchronousDonutProvider2Factory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-provider-2");
+ }
+
+ /**
+ * Return the (asynchronous) donut event provider factory.
+ *
+ * @return the (asynchronous) donut event provider factory
+ */
+ public Factory getDonutEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "donut-event-provider");
+ }
+
+ /**
+ * Return the synchronous donut event provider factory.
+ *
+ * @return the synchronous donut event provider factory
+ */
+ public Factory getSynchronousDonutEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-event-provider");
+ }
+
+ /**
+ * Return the event provider factory.
+ *
+ * @return the event provider factory
+ */
+ public Factory getEventProviderFactory() {
+ return m_ipojoHelper.getFactory("event-provider");
+ }
+
+ /**
+ * Return the synchronous event provider factory.
+ *
+ * @return the synchronous event provider factory
+ */
+ public Factory getSynchronousEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-event-provider");
+ }
+
+ /**
+ * Return the donut consumer factory.
+ *
+ * @return the donut consumer factory
+ */
+ public Factory getDonutConsumerFactory() {
+ return m_ipojoHelper.getFactory("donut-consumer");
+ }
+
+ /**
+ * Return the donut consumer factory using dataKey
+ * and dataType.
+ *
+ * @return the donut consumer factory
+ */
+ public Factory getDonutConsumer2Factory() {
+ return m_ipojoHelper.getFactory("donut-consumer-2");
+ }
+
+ /**
+ * Return the donut event consumer factory.
+ *
+ * @return the donut event consumer factory
+ */
+ public Factory getDonutEventConsumerFactory() {
+ return m_ipojoHelper.getFactory(
+ "donut-event-consumer");
+ }
+
+ /**
+ * Return the event consumer factory.
+ *
+ * @return the event consumer factory
+ */
+ public Factory getEventConsumerFactory() {
+ return m_ipojoHelper.getFactory("event-consumer");
+ }
+
+ /**
+ * Return the event tracker.
+ *
+ * @return the event consumer factory
+ */
+ public Factory getEventTrackerFactory() {
+ return m_ipojoHelper.getFactory("event-tracker");
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java
new file mode 100644
index 0000000..c000435
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java
@@ -0,0 +1,958 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+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.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestBadConfigurations extends Common {
+
+ /**
+ * The namespace of the Event admin handler.
+ */
+ private static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event";
+ /**
+ * The utility class instance.
+ */
+ public EahTestUtils m_utils;
+ /**
+ * The available components.
+ */
+ private Element[] m_components;
+ /**
+ * The description of a component that uses an event publisher.
+ */
+ private Element m_provider;
+ /**
+ * The event publisher description.
+ */
+ private Element m_publisher;
+ /**
+ * The name attribute of the event publisher.
+ */
+ private Attribute m_publisherName;
+ /**
+ * The field attribute of the event publisher.
+ */
+ private Attribute m_publisherField;
+ /**
+ * The topics attribute of the event publisher.
+ */
+ private Attribute m_publisherTopics;
+ /**
+ * The data-key attribute of the event publisher.
+ */
+ private Attribute m_publisherDataKey;
+ /**
+ * The synchronous attribute of the event publisher.
+ */
+ private Attribute m_publisherSynchronous;
+ /**
+ * The description of a component that uses an event subscriber.
+ */
+ private Element m_consumer;
+ /**
+ * The event subscriber description.
+ */
+ private Element m_subscriber;
+ /**
+ * The name attribute of the event subscriber.
+ */
+ private Attribute m_subscriberName;
+ /**
+ * The callback attribute of the event subscriber.
+ */
+ private Attribute m_subscriberCallback;
+ /**
+ * The topics attribute of the event subscriber.
+ */
+ private Attribute m_subscriberTopics;
+ /**
+ * The data-key attribute of the event subscriber.
+ */
+ private Attribute m_subscriberDataKey;
+ /**
+ * The data-type attribute of the event subscriber.
+ */
+ private Attribute m_subscriberDataType;
+
+ private Element getManipulationForComponent(String compName) {
+ for (int i = 0; i < m_components.length; i++) {
+ if (m_components[i].containsAttribute("name")
+ && m_components[i].getAttribute("name").equals(compName)) {
+ return m_components[i].getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Initialization before test cases.
+ * <p/>
+ * Create all the instances
+ */
+ @Before
+ public void setUp() {
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ /**
+ * Get the list of available components.
+ */
+ try {
+ String header = (String) getTestBundle().getHeaders().get(
+ "iPOJO-Components");
+ m_components = ManifestMetadataParser.parseHeaderMetadata(header)
+ .getElements("component");
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ /**
+ * Initialize the standard publishing component (based on the
+ * asynchronous donut provider).
+ */
+ m_provider = new Element("component", "");
+ m_provider.addAttribute(new Attribute("className",
+ "org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"));
+ m_provider.addAttribute(new Attribute("name",
+ "standard donut provider for bad tests"));
+
+ // The provided service of the publisher
+ Element providesDonutProvider = new Element("provides", "");
+ providesDonutProvider.addAttribute(new Attribute("interface",
+ "org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider"));
+ Element providesDonutProviderProperty = new Element("property", "");
+ providesDonutProviderProperty
+ .addAttribute(new Attribute("name", "name"));
+ providesDonutProviderProperty.addAttribute(new Attribute("field",
+ "m_name"));
+ providesDonutProviderProperty.addAttribute(new Attribute("value",
+ "Unknown donut vendor"));
+ providesDonutProvider.addElement(providesDonutProviderProperty);
+ m_provider.addElement(providesDonutProvider);
+
+ // The event publisher, corresponding to the following description :
+ // <ev:publisher name="donut-publisher" field="m_publisher"
+ // topics="food/donuts" data-key="food" synchronous="false"/>
+ m_publisher = new Element("publisher", NAMESPACE);
+ m_publisherName = new Attribute("name", "donut-publisher");
+ m_publisherField = new Attribute("field", "m_publisher");
+ m_publisherTopics = new Attribute("topics", "food/donuts");
+ m_publisherDataKey = new Attribute("data-key", "food");
+ m_publisherSynchronous = new Attribute("synchronous", "false");
+ m_publisher.addAttribute(m_publisherName);
+ m_publisher.addAttribute(m_publisherField);
+ m_publisher.addAttribute(m_publisherTopics);
+ m_publisher.addAttribute(m_publisherDataKey);
+ m_publisher.addAttribute(m_publisherSynchronous);
+ m_provider.addElement(m_publisher);
+
+ m_provider.addElement(getManipulationForComponent("donut-provider"));
+
+ /**
+ * Initialize the standard subscribing component (based on the donut
+ * consumer).
+ */
+ m_consumer = new Element("component", "");
+ m_consumer.addAttribute(new Attribute("className",
+ "org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"));
+ m_consumer.addAttribute(new Attribute("name",
+ "standard donut consumer for bad tests"));
+
+ // The provided service of the publisher
+ Element providesDonutConsumer = new Element("provides", "");
+ providesDonutConsumer.addAttribute(new Attribute("interface",
+ "org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer"));
+ Element providesDonutConsumerNameProperty = new Element("property", "");
+ providesDonutConsumerNameProperty.addAttribute(new Attribute("name",
+ "name"));
+ providesDonutConsumerNameProperty.addAttribute(new Attribute("field",
+ "m_name"));
+ providesDonutConsumerNameProperty.addAttribute(new Attribute("value",
+ "Unknown donut consumer"));
+ providesDonutConsumer.addElement(providesDonutConsumerNameProperty);
+ Element providesDonutConsumerSlowProperty = new Element("property", "");
+ providesDonutConsumerSlowProperty.addAttribute(new Attribute("name",
+ "slow"));
+ providesDonutConsumerSlowProperty.addAttribute(new Attribute("field",
+ "m_isSlow"));
+ providesDonutConsumerSlowProperty.addAttribute(new Attribute("value",
+ "false"));
+ providesDonutConsumer.addElement(providesDonutConsumerSlowProperty);
+ m_consumer.addElement(providesDonutConsumer);
+
+ // The event publisher, corresponding to the following description :
+ // <ev:subscriber name="donut-subscriber" callback="receiveDonut"
+ // topics="food/donuts" data-key="food"
+ // data-type="org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut"/>
+ m_subscriber = new Element("subscriber", NAMESPACE);
+ m_subscriberName = new Attribute("name", "donut-subscriber");
+ m_subscriberCallback = new Attribute("callback", "receiveDonut");
+ m_subscriberTopics = new Attribute("topics", "food/donuts");
+ m_subscriberDataKey = new Attribute("data-key", "food");
+ m_subscriberDataType = new Attribute("data-type",
+ "org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut");
+ m_subscriber.addAttribute(m_subscriberName);
+ m_subscriber.addAttribute(m_subscriberCallback);
+ m_subscriber.addAttribute(m_subscriberTopics);
+ m_subscriber.addAttribute(m_subscriberDataKey);
+ m_subscriber.addAttribute(m_subscriberDataType);
+ m_consumer.addElement(m_subscriber);
+
+ m_consumer.addElement(getManipulationForComponent("donut-consumer"));
+ }
+
+ /**
+ * Test the base configuration is correct to be sure the bad tests will fail
+ * because of they are really bad, and not because of an other application
+ * error.
+ * <p/>
+ * This test simply create a provider and a consumer instance, send one
+ * event and check it is received.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testGoodConfig()
+ throws ConfigurationException, UnacceptableConfiguration,
+ MissingHandlerException {
+ /**
+ * Create the provider and the consumer instances.
+ */
+ Dictionary properties = new Hashtable();
+
+ // Provider
+ ComponentFactory providerFactory = new ComponentFactory(bc,
+ m_provider);
+ providerFactory.start();
+ properties.put("instance.name", "Emperor of donuts");
+ ComponentInstance providerInstance = providerFactory
+ .createComponentInstance(properties);
+ ServiceReference providerService = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), providerInstance.getInstanceName());
+ DonutProvider provider = (DonutProvider) bc
+ .getService(providerService);
+
+ // The consumer
+ properties = new Hashtable();
+ ComponentFactory consumerFactory = new ComponentFactory(bc,
+ m_consumer);
+ consumerFactory.start();
+ properties.put("instance.name", "Homer Simpson");
+ properties.put("slow", "false");
+ ComponentInstance consumerInstance = consumerFactory
+ .createComponentInstance(properties);
+ ServiceReference consumerService = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), consumerInstance.getInstanceName());
+ DonutConsumer consumer = (DonutConsumer) bc
+ .getService(consumerService);
+
+ /**
+ * Test the normal behaviour of the instances.
+ */
+ consumer.clearDonuts();
+ Donut sentDonut = provider.sellDonut();
+ Donut receivedDonut = consumer.waitForDonut();
+ assertEquals("The received donut must be the same as the sent one.",
+ sentDonut, receivedDonut);
+
+ /**
+ * Destroy component's instances.
+ */
+ bc.ungetService(providerService);
+ providerInstance.dispose();
+ bc.ungetService(consumerService);
+ consumerInstance.dispose();
+ providerFactory.stop();
+ consumerFactory.stop();
+ }
+
+ /**
+ * Try to create a publisher with no name.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithoutName()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher
+ m_publisher.removeAttribute(m_publisherName);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when no name is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.addAttribute(m_publisherName);
+ }
+ }
+
+ /**
+ * Try to create a publisher with no field.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithoutField()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher
+ m_publisher.removeAttribute(m_publisherField);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when no field is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.addAttribute(m_publisherField);
+ }
+ }
+
+ /**
+ * Try to create a publisher with an unexisting field.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithUnexistingField()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher and replace with an
+ // unexisting field name
+ m_publisher.removeAttribute(m_publisherField);
+ Attribute unexistingField = new Attribute("field", "m_unexistingField");
+ m_publisher.addAttribute(unexistingField);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when an unexisting field is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.removeAttribute(unexistingField);
+ m_publisher.addAttribute(m_publisherField);
+ }
+ }
+
+ /**
+ * Try to create a publisher with a bad typed field.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithBadTypedField()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher and replace with an
+ // bad typed field name
+ m_publisher.removeAttribute(m_publisherField);
+ Attribute badTypedField = new Attribute("field", "m_name");
+ m_publisher.addAttribute(badTypedField);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when an bad typed field is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.removeAttribute(badTypedField);
+ m_publisher.addAttribute(m_publisherField);
+ }
+ }
+
+ /**
+ * Try to create a publisher instance without topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithoutTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the publisher
+ m_publisher.removeAttribute(m_publisherTopics);
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ fact.start();
+
+ // Try to create an instance without specified topics
+ Dictionary conf = new Hashtable();
+ conf.put("instance.name", "provider without topics");
+
+ ComponentInstance instance;
+ try {
+ instance = fact.createComponentInstance(conf);
+ // Should not be executed
+ instance.dispose();
+ fail("The factory must not create instance without specified topics.");
+ } catch (ConfigurationException e) {
+ // OK
+ } finally {
+ fact.stop();
+ // Restore the original state of the publisher
+ m_publisher.addAttribute(m_publisherTopics);
+ }
+ }
+
+ /**
+ * Try to create a publisher with malformed topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithMalformedTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the publisher and replace with a
+ // malformed one
+ m_publisher.removeAttribute(m_publisherTopics);
+ Attribute malformedTopics = new Attribute("topics",
+ "| |\\| \\/ /-\\ |_ | |)");
+ m_publisher.addAttribute(malformedTopics);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when invalid topics are specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.removeAttribute(malformedTopics);
+ m_publisher.addAttribute(m_publisherTopics);
+ }
+ }
+
+ /**
+ * Try to create a publisher with a pattern topic (ending with '*') instead of a fixed topic.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithPatternTopic()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the publisher and replace with a
+ // malformed one
+ m_publisher.removeAttribute(m_publisherTopics);
+ Attribute malformedTopics = new Attribute("topics",
+ "a/pattern/topic/*");
+ m_publisher.addAttribute(malformedTopics);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when invalid topics are specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_publisher.removeAttribute(malformedTopics);
+ m_publisher.addAttribute(m_publisherTopics);
+ }
+ }
+
+ /**
+ * Try to create a publisher with malformed instance topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithMalformedInstanceTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the publisher and replace with a
+ // malformed one
+ m_publisher.removeAttribute(m_publisherTopics);
+ ComponentFactory fact = new ComponentFactory(bc, m_provider);
+ fact.start();
+
+ // Try to create an instance with malformed specified topics
+ Dictionary conf = new Hashtable();
+ conf.put("instance.name", "provider with malformed topics");
+ Dictionary topics = new Hashtable();
+ topics.put("donut-publisher", "| |\\| \\/ /-\\ |_ | |)");
+ conf.put("event.topics", topics);
+
+ ComponentInstance instance;
+ try {
+ instance = fact.createComponentInstance(conf);
+ // Should not be executed
+ instance.dispose();
+ fail("The factory must not create instance with invalid specified topics.");
+ } catch (ConfigurationException e) {
+ // OK
+ } finally {
+ fact.stop();
+ // Restore the original state of the publisher
+ m_publisher.addAttribute(m_publisherTopics);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with no name.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithoutName()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher
+ m_subscriber.removeAttribute(m_subscriberName);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when no name is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_subscriber.addAttribute(m_subscriberName);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with no callback.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithoutCallback()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the name attribute of the publisher
+ m_subscriber.removeAttribute(m_subscriberCallback);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when no callback is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the publisher
+ m_subscriber.addAttribute(m_subscriberCallback);
+ }
+ }
+
+ /**
+ * Try to create a subscriber instance without topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithoutTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the subscriber
+ m_subscriber.removeAttribute(m_subscriberTopics);
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ fact.start();
+
+ // Try to create an instance without specified topics
+ Dictionary conf = new Hashtable();
+ conf.put("instance.name", "consumer without topics");
+ conf.put("slow", "false");
+
+ ComponentInstance instance;
+ try {
+ instance = fact.createComponentInstance(conf);
+ // Should not be executed
+ instance.dispose();
+ fail("The factory must not create instance without specified topics.");
+ } catch (ConfigurationException e) {
+ // OK
+ } finally {
+ fact.stop();
+ // Restore the original state of the subscriber
+ m_subscriber.addAttribute(m_subscriberTopics);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with malformed topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithMalformedTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the subscriber and replace with a
+ // malformed one
+ m_subscriber.removeAttribute(m_subscriberTopics);
+ Attribute malformedTopics = new Attribute("topics",
+ "| |\\| \\/ /-\\ |_ | |)");
+ m_subscriber.addAttribute(malformedTopics);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when invalid topics are specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the subscriber
+ m_subscriber.removeAttribute(malformedTopics);
+ m_subscriber.addAttribute(m_subscriberTopics);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with malformed instance topics.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithMalformedInstanceTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the subscriber and replace with a
+ // malformed one
+ m_subscriber.removeAttribute(m_subscriberTopics);
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ fact.start();
+
+ // Try to create an instance with malformed specified topics
+ Dictionary conf = new Hashtable();
+ conf.put("instance.name", "consumer with malformed topics");
+ Dictionary topics = new Hashtable();
+ topics.put("donut-subscriber", "| |\\| \\/ /-\\ |_ | |)");
+ conf.put("event.topics", topics);
+
+ ComponentInstance instance;
+ try {
+ instance = fact.createComponentInstance(conf);
+ // Should not be executed
+ instance.dispose();
+ fail("The factory must not create instance with invalid specified topics.");
+ } catch (ConfigurationException e) {
+ // OK
+ } finally {
+ fact.stop();
+ // Restore the original state of the subscriber
+ m_subscriber.addAttribute(m_subscriberTopics);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with unknown data type.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithUnknownDataType()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the data-type attribute of the subscriber and replace with a
+ // malformed one
+ m_subscriber.removeAttribute(m_subscriberDataType);
+ Attribute unknownType = new Attribute("data-type", "org.unknown.Clazz");
+ m_subscriber.addAttribute(unknownType);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when unknown data type is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the subscriber
+ m_subscriber.removeAttribute(unknownType);
+ m_subscriber.addAttribute(m_subscriberDataType);
+ }
+ }
+
+ /**
+ * Try to create a subscriber with a data type that does not match with the
+ * callback parameter type.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithUnappropriatedDataType()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the data-type attribute of the subscriber and replace with a
+ // malformed one
+ m_subscriber.removeAttribute(m_subscriberDataType);
+ Attribute unknownType = new Attribute("data-type", "java.lang.String");
+ m_subscriber.addAttribute(unknownType);
+
+ // Create and try to start the factory
+ ComponentFactory fact = new ComponentFactory(bc, m_consumer);
+ try {
+ fact.start();
+ // Should not be executed
+ fact.stop();
+ fail("The factory must not start when unappropriated data type is specified.");
+ } catch (IllegalStateException e) {
+ // OK
+ } finally {
+ // Restore the original state of the subscriber
+ m_subscriber.removeAttribute(unknownType);
+ m_subscriber.addAttribute(m_subscriberDataType);
+ }
+ }
+
+ // DEBUG
+ public void dumpElement(String message, Element root) {
+ System.err.println(message + "\n" + dumpElement(0, root));
+ }
+
+ // DEBUG
+ private String dumpElement(int level, Element element) {
+ StringBuilder sb = new StringBuilder();
+ // Enter tag
+ for (int i = 0; i < level; i++) {
+ sb.append(" ");
+ }
+ sb.append('<');
+ sb.append(element.getName());
+ Attribute[] attributes = element.getAttributes();
+ for (int i = 0; i < attributes.length; i++) {
+ Attribute attribute = attributes[i];
+ sb.append(' ');
+ sb.append(attribute.getName());
+ sb.append('=');
+ sb.append(attribute.getValue());
+ }
+ sb.append(">\n");
+ // Children
+ Element[] elements = element.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ sb.append(dumpElement(level + 1, elements[i]));
+ }
+ // Exit tag
+ for (int i = 0; i < level; i++) {
+ sb.append(" ");
+ }
+ sb.append("</" + element.getName() + ">\n");
+ return sb.toString();
+ }
+
+ /**
+ * Creates a subscriber listening on a pattern topic (ending with '*').
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Dictionary properties = new Hashtable();
+ Dictionary topics = new Hashtable();
+
+ // Create the donut consumer instance, listening on a pattern topic
+ properties.put("instance.name", "subscriber with pattern topic");
+ topics.put("donut-subscriber", "a/pattern/topic/*rf");
+ properties.put("event.topics", topics);
+ ComponentInstance instance = null;
+ try {
+ instance = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Should not been executed
+ instance.dispose();
+ fail("An invalid topic scope was accepted)");
+
+ } catch (ConfigurationException e) {
+ // Nothing to do
+ }
+
+ properties = new Hashtable();
+ topics = new Hashtable();
+
+ // Create the donut consumer instance, listening on a pattern topic
+ properties.put("instance.name", "subscriber with pattern topic");
+ topics.put("donut-subscriber", "a/pattern/*topic/rf");
+ properties.put("event.topics", topics);
+
+ try {
+ instance = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+ instance.dispose();
+ fail("An invalid topic scope was accepted (2)");
+ } catch (ConfigurationException e) {
+ // Nothing to do
+ }
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java
new file mode 100644
index 0000000..f9fb155
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java
@@ -0,0 +1,714 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestEventAdminHandler extends Common {
+
+ /**
+ * The number of providers to test.
+ */
+ private static final int NUMBER_OF_PROVIDERS = 6;
+ /**
+ * The number of providers using the event admin handler to test.
+ */
+ private static final int NUMBER_OF_EAH_PROVIDERS = 4;
+ /**
+ * The number of consumers to test.
+ */
+ private static final int NUMBER_OF_CONSUMERS = 6;
+ /**
+ * The number of synchronous providers to test.
+ */
+ private static final int NUMBER_OF_SYNCHRONOUS_PROVIDERS = 3;
+ /**
+ * The number of slow consumers to test.
+ */
+ private static final int NUMBER_OF_QUICK_CONSUMERS = 3;
+ /**
+ * The list of topics to test.
+ */
+ private static final String[] TOPICS_LIST = {"foo", "bar", "nut",
+ "foo,bar", "bar,nut", "foo,nut", "foo,bar,nut"};
+ /**
+ * The utility class instance.
+ */
+ public EahTestUtils m_utils;
+ /**
+ * The providers' instances.
+ */
+ private ComponentInstance[] m_providersInstances;
+ /**
+ * The providers' service references.
+ */
+ private ServiceReference[] m_providersServices;
+ /**
+ * The providers' services.
+ */
+ private DonutProvider[] m_providers;
+ /**
+ * The synchronous providers' services.
+ */
+ private DonutProvider[] m_synchronousProviders;
+ /**
+ * The instances of providers that uses the event admin handler.
+ */
+ private ComponentInstance[] m_eahProvidersInstances;
+ /**
+ * The services of the providers that uses the event admin handler.
+ */
+ private DonutProvider[] m_eahProviders;
+ /**
+ * The synchronous donut event provider service.
+ */
+ private DonutProvider m_synchronousDonutEventProvider;
+ /**
+ * The consumers' instances.
+ */
+ private ComponentInstance[] m_consumersInstances;
+ /**
+ * The consumers' service references.
+ */
+ private ServiceReference[] m_consumersServices;
+ /**
+ * The consumers' services.
+ */
+ private DonutConsumer[] m_consumers;
+ /**
+ * The slow consumers' services.
+ */
+ private DonutConsumer[] m_quickConsumers;
+ /**
+ * The event tracker' instances.
+ */
+ private ComponentInstance m_eventTrackerInstance;
+ /**
+ * The event tracker' service references.
+ */
+ private ServiceReference m_eventTrackerService;
+ /**
+ * The event tracker service.
+ */
+ private EventTracker m_eventTracker;
+ /**
+ * The filtered consumers' instances.
+ */
+ private ComponentInstance[] m_filteredConsumersInstances;
+ /**
+ * The filtered consumers' service references.
+ */
+ private ServiceReference[] m_filteredConsumersServices;
+ /**
+ * The filtered consumers' services.
+ */
+ private DonutConsumer[] m_filteredConsumers;
+ /**
+ * The providers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsProvidersInstances;
+ /**
+ * The providers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsProvidersServices;
+ /**
+ * The providers' service with specified topics.
+ */
+ private DonutProvider[] m_topicsProviders;
+ /**
+ * The provider that send donuts on the "foo" topic.
+ */
+ private DonutProvider m_fooProvider;
+ /**
+ * The provider that send donuts on the "bar" topic.
+ */
+ private DonutProvider m_barProvider;
+ /**
+ * The provider that send donuts on the "nut" topic.
+ */
+ private DonutProvider m_nutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar" topics.
+ */
+ private DonutProvider m_fooBarProvider;
+ /**
+ * The provider that send donuts on the "bar,nut" topics.
+ */
+ private DonutProvider m_barNutProvider;
+ /**
+ * The provider that send donuts on the "foo,nut" topics.
+ */
+ private DonutProvider m_fooNutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar,nut" topics.
+ */
+ private DonutProvider m_fooBarNutProvider;
+ /**
+ * The consumers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsConsumersInstances;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsConsumersServices;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private DonutConsumer[] m_topicsConsumers;
+ /**
+ * The consumer that receive donuts on the "foo" topic.
+ */
+ private DonutConsumer m_fooConsumer;
+ /**
+ * The consumer that receive donuts on the "bar" topic.
+ */
+ private DonutConsumer m_barConsumer;
+ /**
+ * The consumer that receive donuts on the "nut" topic.
+ */
+ private DonutConsumer m_nutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar" topics.
+ */
+ private DonutConsumer m_fooBarConsumer;
+ /**
+ * The consumer that receive donuts on the "bar,nut" topics.
+ */
+ private DonutConsumer m_barNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,nut" topics.
+ */
+ private DonutConsumer m_fooNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar,nut" topics.
+ */
+ private DonutConsumer m_fooBarNutConsumer;
+
+ /**
+ * Initialization before test cases.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ Dictionary properties = new Hashtable();
+
+ // All the providers
+ m_providersInstances = new ComponentInstance[NUMBER_OF_PROVIDERS];
+ m_providersServices = new ServiceReference[NUMBER_OF_PROVIDERS];
+ m_providers = new DonutProvider[NUMBER_OF_PROVIDERS];
+ m_synchronousProviders = new DonutProvider[NUMBER_OF_SYNCHRONOUS_PROVIDERS];
+ m_eahProviders = new DonutProvider[NUMBER_OF_EAH_PROVIDERS];
+ m_eahProvidersInstances = new ComponentInstance[NUMBER_OF_EAH_PROVIDERS];
+ m_topicsProvidersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsProvidersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsProviders = new DonutProvider[TOPICS_LIST.length];
+
+ // Create the (asynchronous) donut provider
+ properties.put("instance.name", "asynchronous donut provider");
+ m_providersInstances[0] = m_utils.getDonutProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut provider");
+ m_providersInstances[1] = m_utils.getSynchronousDonutProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous donut event provider");
+ m_providersInstances[2] = m_utils.getDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut event provider");
+ m_providersInstances[3] = m_utils
+ .getSynchronousDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous event provider");
+ m_providersInstances[4] = m_utils.getEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous event provider");
+ m_providersInstances[5] = m_utils.getSynchronousEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ m_providersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .getService(m_providersServices[i]);
+ }
+ m_synchronousProviders[0] = m_providers[1];
+ m_synchronousProviders[1] = m_providers[3];
+ m_synchronousProviders[2] = m_providers[5];
+ m_eahProviders[0] = m_providers[0];
+ m_eahProviders[1] = m_providers[1];
+ m_eahProviders[2] = m_providers[2];
+ m_eahProviders[3] = m_providers[3];
+ m_eahProvidersInstances[0] = m_providersInstances[0];
+ m_eahProvidersInstances[1] = m_providersInstances[1];
+ m_eahProvidersInstances[2] = m_providersInstances[2];
+ m_eahProvidersInstances[3] = m_providersInstances[3];
+ m_synchronousDonutEventProvider = m_providers[3];
+
+ // All the consumers
+ m_consumersInstances = new ComponentInstance[NUMBER_OF_CONSUMERS];
+ m_consumersServices = new ServiceReference[NUMBER_OF_CONSUMERS];
+ m_consumers = new DonutConsumer[NUMBER_OF_CONSUMERS];
+ m_quickConsumers = new DonutConsumer[NUMBER_OF_QUICK_CONSUMERS];
+ m_filteredConsumersInstances = new ComponentInstance[Donut.FLAVOURS.length];
+ m_filteredConsumersServices = new ServiceReference[Donut.FLAVOURS.length];
+ m_filteredConsumers = new DonutConsumer[Donut.FLAVOURS.length];
+ m_topicsConsumersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsConsumersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsConsumers = new DonutConsumer[TOPICS_LIST.length];
+
+ // Create the (quick) donut consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut consumer");
+ m_consumersInstances[0] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut event consumer");
+ m_consumersInstances[1] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick event consumer");
+ m_consumersInstances[2] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut consumer
+ properties = new Hashtable();
+ properties.put("slow", Boolean.TRUE);
+ properties.put("instance.name", "slow donut consumer");
+ m_consumersInstances[3] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow donut event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[4] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[5] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .getService(m_consumersServices[i]);
+ }
+ m_quickConsumers[0] = m_consumers[0];
+ m_quickConsumers[1] = m_consumers[1];
+ m_quickConsumers[2] = m_consumers[2];
+
+ // Create the event tracker
+ properties = new Hashtable();
+ properties.put("instance.name", "event tracker");
+ m_eventTrackerInstance = m_utils.getEventTrackerFactory()
+ .createComponentInstance(properties);
+ m_eventTrackerService = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .getService(m_eventTrackerService);
+
+ // Create the filtered consumer
+ Dictionary filter = new Hashtable();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ String flavour = Donut.FLAVOURS[i];
+ properties = new Hashtable();
+ filter.put("donut-event-subscriber", "(flavour=" + flavour + ")");
+ properties.put("instance.name", flavour + " donut consumer");
+ properties.put("event.filter", filter);
+ m_filteredConsumersInstances[i] = m_utils
+ .getDonutEventConsumerFactory().createComponentInstance(
+ properties);
+ m_filteredConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(
+ DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .getService(m_filteredConsumersServices[i]);
+ }
+
+ // Create the providers and consumers selling and receiving donuts on
+ // specific topics
+ Dictionary topics = new Hashtable();
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ String topicsString = TOPICS_LIST[i];
+ properties = new Hashtable();
+ // Create provider
+ topics.put("donut-publisher", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut provider");
+ m_topicsProvidersInstances[i] = m_utils
+ .getSynchronousDonutProviderFactory()
+ .createComponentInstance(properties);
+ m_topicsProvidersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .getService(m_topicsProvidersServices[i]);
+
+ // Create consumer
+ properties = new Hashtable();
+ topics.put("donut-subscriber", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut consumer");
+
+ m_topicsConsumersInstances[i] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+ m_topicsConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .getService(m_topicsConsumersServices[i]);
+ topics.remove("donut-subscriber");
+ }
+
+ m_fooProvider = m_topicsProviders[0];
+ m_barProvider = m_topicsProviders[1];
+ m_nutProvider = m_topicsProviders[2];
+ m_fooBarProvider = m_topicsProviders[3];
+ m_barNutProvider = m_topicsProviders[4];
+ m_fooNutProvider = m_topicsProviders[5];
+ m_fooBarNutProvider = m_topicsProviders[6];
+ m_fooConsumer = m_topicsConsumers[0];
+ m_barConsumer = m_topicsConsumers[1];
+ m_nutConsumer = m_topicsConsumers[2];
+ m_fooBarConsumer = m_topicsConsumers[3];
+ m_barNutConsumer = m_topicsConsumers[4];
+ m_fooNutConsumer = m_topicsConsumers[5];
+ m_fooBarNutConsumer = m_topicsConsumers[6];
+
+ }
+
+ /**
+ * Creates a subscriber listening on a pattern topic (ending with '*').
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Dictionary properties = new Hashtable();
+ Dictionary topics = new Hashtable();
+
+ // Create the donut consumer instance, listening on a pattern topic
+ properties.put("instance.name", "subscriber with pattern topic");
+ topics.put("donut-subscriber", "a/pattern/topic/*");
+ properties.put("event.topics", topics);
+
+ ComponentInstance instance = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+ instance.dispose();
+ }
+
+ /**
+ * Test the event handler reliability by sending events with all kinds of
+ * publisher and check they are received by all kinds of subscriber.
+ */
+ @Test
+ public void testReliability() {
+
+ // Flush donut list for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumers[i].clearDonuts();
+ }
+
+ // Send a lot of donut with each provider
+ List sentDonuts = new ArrayList(NUMBER_OF_PROVIDERS
+ * EahTestUtils.NUMBER_OF_TESTS);
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ sentDonuts.add(m_providers[i].sellDonut());
+ }
+ }
+
+ // Wait a respectable amount of time
+ EahTestUtils.sleep(EahTestUtils.BLACK_LIST_TIME
+ + EahTestUtils.A_LONG_TIME);
+
+ // Collect all received donuts for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ List receivedDonuts = Arrays.asList(m_consumers[i].getAllDonuts());
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts.",
+ sentDonuts.size(), receivedDonuts.size());
+ assertTrue("The receiver must have eaten all sent donuts.",
+ receivedDonuts.containsAll(sentDonuts));
+ }
+ }
+
+ /**
+ * Test the synchronism of event sending for the component.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ public void testSynchronism() {
+
+ // Flush donut list for quick consumers
+ for (int i = 0; i < NUMBER_OF_QUICK_CONSUMERS; i++) {
+ m_quickConsumers[i].clearDonuts();
+ }
+
+ // Send a lot of donuts and check they are immediately received.
+ Donut sentDonut;
+ Donut receivedDonut;
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ for (int j = 0; j < NUMBER_OF_SYNCHRONOUS_PROVIDERS; j++) {
+ sentDonut = m_synchronousProviders[j].sellDonut();
+ for (int k = 0; k < NUMBER_OF_QUICK_CONSUMERS; k++) {
+ receivedDonut = m_quickConsumers[k].getDonut();
+ assertEquals(
+ "The donut must have been received immediately and be the be the same as the sent one.",
+ sentDonut, receivedDonut);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test that the received events contains the instance name of the sender.
+ */
+ @Test
+ public void testInstanceName() {
+
+ // Flush event list of the event tracker
+ m_eventTracker.clearEvents();
+
+ // Send donuts and check the sender instance name
+ Event receivedEvent;
+ for (int i = 0; i < NUMBER_OF_EAH_PROVIDERS; i++) {
+ m_eahProviders[i].sellDonut();
+ receivedEvent = m_eventTracker.waitForEvent();
+ assertEquals(
+ "The instance name property of the received message must be the same as the sender instance name.",
+ m_eahProvidersInstances[i].getInstanceName(), receivedEvent
+ .getProperty("publisher.instance.name"));
+ }
+ }
+
+ /**
+ * Test the event filtering.
+ * <p/>
+ * This test send donuts with different flavours. Each filtered consumer
+ * must receive only a certain kind of donut. Of course, all donuts must
+ * have been received too.
+ */
+ @Test
+ public void testFilters() {
+
+ // The sent donuts, sorted by flavour
+ List[] sentDonuts = new List[Donut.FLAVOURS.length];
+
+ // Flush donut list for each filtered consumer
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ m_filteredConsumers[i].clearDonuts();
+ sentDonuts[i] = new ArrayList(EahTestUtils.NUMBER_OF_TESTS
+ / Donut.FLAVOURS.length);
+ }
+
+ // Send donuts
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ Donut donut = m_synchronousDonutEventProvider.sellDonut();
+ sentDonuts[EahTestUtils.flavourIndex(donut.getFlavour())]
+ .add(donut);
+ }
+
+ // Check the received donuts
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ Donut[] receivedDonuts = m_filteredConsumers[i].getAllDonuts();
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts with the matching flavour.",
+ sentDonuts[i].size(), receivedDonuts.length);
+ assertTrue(
+ "The receiver must have eaten all sent donuts matching the wanted flavour.",
+ Arrays.asList(receivedDonuts).containsAll(sentDonuts[i]));
+ }
+
+ }
+
+ /**
+ * Test the event topic.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ public void testTopics() {
+
+ // The sent donuts, sorted by topic
+ int foos = 0;
+ int bars = 0;
+ int nuts = 0;
+
+ // Flush consumers
+ m_fooConsumer.clearDonuts();
+ m_barConsumer.clearDonuts();
+ m_nutConsumer.clearDonuts();
+ m_fooBarConsumer.clearDonuts();
+ m_barNutConsumer.clearDonuts();
+ m_fooNutConsumer.clearDonuts();
+ m_fooBarNutConsumer.clearDonuts();
+
+ // Send donuts
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ m_fooProvider.sellDonut();
+ foos++;
+
+ m_barProvider.sellDonut();
+ bars++;
+
+ m_nutProvider.sellDonut();
+ nuts++;
+
+ m_fooBarProvider.sellDonut();
+ foos++;
+ bars++;
+
+ m_barNutProvider.sellDonut();
+ bars++;
+ nuts++;
+
+ m_fooNutProvider.sellDonut();
+ foos++;
+ nuts++;
+
+ m_fooBarNutProvider.sellDonut();
+ foos++;
+ bars++;
+ nuts++;
+ }
+
+ // Check received donuts
+ assertEquals("The number of received donuts must be correct.", foos,
+ m_fooConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars,
+ m_barConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", nuts,
+ m_nutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars, m_fooBarConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars
+ + nuts, m_barNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + nuts, m_fooNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars + nuts, m_fooBarNutConsumer.getAllDonuts().length);
+
+ }
+
+ /**
+ * Finalization after test cases.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java
new file mode 100644
index 0000000..ba28e47
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java
@@ -0,0 +1,715 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestEventAdminHandlerWithNewAttributes extends Common {
+
+ /**
+ * The number of providers to test.
+ */
+ private static final int NUMBER_OF_PROVIDERS = 6;
+ /**
+ * The number of providers using the event admin handler to test.
+ */
+ private static final int NUMBER_OF_EAH_PROVIDERS = 4;
+ /**
+ * The number of consumers to test.
+ */
+ private static final int NUMBER_OF_CONSUMERS = 6;
+ /**
+ * The number of synchronous providers to test.
+ */
+ private static final int NUMBER_OF_SYNCHRONOUS_PROVIDERS = 3;
+ /**
+ * The number of slow consumers to test.
+ */
+ private static final int NUMBER_OF_QUICK_CONSUMERS = 3;
+ /**
+ * The list of topics to test.
+ */
+ private static final String[] TOPICS_LIST = {"foo", "bar", "nut",
+ "foo,bar", "bar,nut", "foo,nut", "foo,bar,nut"};
+ /**
+ * The utility class instance.
+ */
+ public EahTestUtils m_utils;
+ /**
+ * The providers' instances.
+ */
+ private ComponentInstance[] m_providersInstances;
+ /**
+ * The providers' service references.
+ */
+ private ServiceReference[] m_providersServices;
+ /**
+ * The providers' services.
+ */
+ private DonutProvider[] m_providers;
+ /**
+ * The synchronous providers' services.
+ */
+ private DonutProvider[] m_synchronousProviders;
+ /**
+ * The instances of providers that uses the event admin handler.
+ */
+ private ComponentInstance[] m_eahProvidersInstances;
+ /**
+ * The services of the providers that uses the event admin handler.
+ */
+ private DonutProvider[] m_eahProviders;
+ /**
+ * The synchronous donut event provider service.
+ */
+ private DonutProvider m_synchronousDonutEventProvider;
+ /**
+ * The consumers' instances.
+ */
+ private ComponentInstance[] m_consumersInstances;
+ /**
+ * The consumers' service references.
+ */
+ private ServiceReference[] m_consumersServices;
+ /**
+ * The consumers' services.
+ */
+ private DonutConsumer[] m_consumers;
+ /**
+ * The slow consumers' services.
+ */
+ private DonutConsumer[] m_quickConsumers;
+ /**
+ * The event tracker' instances.
+ */
+ private ComponentInstance m_eventTrackerInstance;
+ /**
+ * The event tracker' service references.
+ */
+ private ServiceReference m_eventTrackerService;
+ /**
+ * The event tracker service.
+ */
+ private EventTracker m_eventTracker;
+ /**
+ * The filtered consumers' instances.
+ */
+ private ComponentInstance[] m_filteredConsumersInstances;
+ /**
+ * The filtered consumers' service references.
+ */
+ private ServiceReference[] m_filteredConsumersServices;
+ /**
+ * The filtered consumers' services.
+ */
+ private DonutConsumer[] m_filteredConsumers;
+ /**
+ * The providers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsProvidersInstances;
+ /**
+ * The providers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsProvidersServices;
+ /**
+ * The providers' service with specified topics.
+ */
+ private DonutProvider[] m_topicsProviders;
+ /**
+ * The provider that send donuts on the "foo" topic.
+ */
+ private DonutProvider m_fooProvider;
+ /**
+ * The provider that send donuts on the "bar" topic.
+ */
+ private DonutProvider m_barProvider;
+ /**
+ * The provider that send donuts on the "nut" topic.
+ */
+ private DonutProvider m_nutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar" topics.
+ */
+ private DonutProvider m_fooBarProvider;
+ /**
+ * The provider that send donuts on the "bar,nut" topics.
+ */
+ private DonutProvider m_barNutProvider;
+ /**
+ * The provider that send donuts on the "foo,nut" topics.
+ */
+ private DonutProvider m_fooNutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar,nut" topics.
+ */
+ private DonutProvider m_fooBarNutProvider;
+ /**
+ * The consumers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsConsumersInstances;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsConsumersServices;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private DonutConsumer[] m_topicsConsumers;
+ /**
+ * The consumer that receive donuts on the "foo" topic.
+ */
+ private DonutConsumer m_fooConsumer;
+ /**
+ * The consumer that receive donuts on the "bar" topic.
+ */
+ private DonutConsumer m_barConsumer;
+ /**
+ * The consumer that receive donuts on the "nut" topic.
+ */
+ private DonutConsumer m_nutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar" topics.
+ */
+ private DonutConsumer m_fooBarConsumer;
+ /**
+ * The consumer that receive donuts on the "bar,nut" topics.
+ */
+ private DonutConsumer m_barNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,nut" topics.
+ */
+ private DonutConsumer m_fooNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar,nut" topics.
+ */
+ private DonutConsumer m_fooBarNutConsumer;
+
+ /**
+ * Initialization before test cases.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ Dictionary properties = new Hashtable();
+
+ // All the providers
+ m_providersInstances = new ComponentInstance[NUMBER_OF_PROVIDERS];
+ m_providersServices = new ServiceReference[NUMBER_OF_PROVIDERS];
+ m_providers = new DonutProvider[NUMBER_OF_PROVIDERS];
+ m_synchronousProviders = new DonutProvider[NUMBER_OF_SYNCHRONOUS_PROVIDERS];
+ m_eahProviders = new DonutProvider[NUMBER_OF_EAH_PROVIDERS];
+ m_eahProvidersInstances = new ComponentInstance[NUMBER_OF_EAH_PROVIDERS];
+ m_topicsProvidersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsProvidersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsProviders = new DonutProvider[TOPICS_LIST.length];
+
+ // Create the (asynchronous) donut provider
+ properties.put("instance.name", "asynchronous donut provider");
+ m_providersInstances[0] = m_utils.getDonutProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut provider");
+ m_providersInstances[1] = m_utils.getSynchronousDonutProvider2Factory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous donut event provider");
+ m_providersInstances[2] = m_utils.getDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut event provider");
+ m_providersInstances[3] = m_utils
+ .getSynchronousDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous event provider");
+ m_providersInstances[4] = m_utils.getEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous event provider");
+ m_providersInstances[5] = m_utils.getSynchronousEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ m_providersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .getService(m_providersServices[i]);
+ }
+ m_synchronousProviders[0] = m_providers[1];
+ m_synchronousProviders[1] = m_providers[3];
+ m_synchronousProviders[2] = m_providers[5];
+ m_eahProviders[0] = m_providers[0];
+ m_eahProviders[1] = m_providers[1];
+ m_eahProviders[2] = m_providers[2];
+ m_eahProviders[3] = m_providers[3];
+ m_eahProvidersInstances[0] = m_providersInstances[0];
+ m_eahProvidersInstances[1] = m_providersInstances[1];
+ m_eahProvidersInstances[2] = m_providersInstances[2];
+ m_eahProvidersInstances[3] = m_providersInstances[3];
+ m_synchronousDonutEventProvider = m_providers[3];
+
+ // All the consumers
+ m_consumersInstances = new ComponentInstance[NUMBER_OF_CONSUMERS];
+ m_consumersServices = new ServiceReference[NUMBER_OF_CONSUMERS];
+ m_consumers = new DonutConsumer[NUMBER_OF_CONSUMERS];
+ m_quickConsumers = new DonutConsumer[NUMBER_OF_QUICK_CONSUMERS];
+
+ m_filteredConsumersInstances = new ComponentInstance[Donut.FLAVOURS.length];
+ m_filteredConsumersServices = new ServiceReference[Donut.FLAVOURS.length];
+ m_filteredConsumers = new DonutConsumer[Donut.FLAVOURS.length];
+ m_topicsConsumersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsConsumersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsConsumers = new DonutConsumer[TOPICS_LIST.length];
+
+ // Create the (quick) donut consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut consumer");
+ m_consumersInstances[0] = m_utils.getDonutConsumer2Factory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut event consumer");
+ m_consumersInstances[1] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick event consumer");
+ m_consumersInstances[2] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut consumer
+ properties = new Hashtable();
+ properties.put("slow", Boolean.TRUE);
+ properties.put("instance.name", "slow donut consumer");
+ m_consumersInstances[3] = m_utils.getDonutConsumer2Factory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow donut event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[4] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[5] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .getService(m_consumersServices[i]);
+ }
+ m_quickConsumers[0] = m_consumers[0];
+ m_quickConsumers[1] = m_consumers[1];
+ m_quickConsumers[2] = m_consumers[2];
+
+ // Create the event tracker
+ properties = new Hashtable();
+ properties.put("instance.name", "event tracker");
+ m_eventTrackerInstance = m_utils.getEventTrackerFactory()
+ .createComponentInstance(properties);
+ m_eventTrackerService = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .getService(m_eventTrackerService);
+
+ // Create the filtered consumer
+ Dictionary filter = new Hashtable();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ String flavour = Donut.FLAVOURS[i];
+ properties = new Hashtable();
+ filter.put("donut-event-subscriber", "(flavour=" + flavour + ")");
+ properties.put("instance.name", flavour + " donut consumer");
+ properties.put("event.filter", filter);
+ m_filteredConsumersInstances[i] = m_utils
+ .getDonutEventConsumerFactory().createComponentInstance(
+ properties);
+ m_filteredConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .getService(m_filteredConsumersServices[i]);
+ }
+
+ // Create the providers and consumers selling and receiving donuts on
+ // specific topics
+ Dictionary topics = new Hashtable();
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ String topicsString = TOPICS_LIST[i];
+ properties = new Hashtable();
+ // Create provider
+ topics.put("donut-publisher", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut provider");
+ m_topicsProvidersInstances[i] = m_utils
+ .getSynchronousDonutProviderFactory()
+ .createComponentInstance(properties);
+ m_topicsProvidersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .getService(m_topicsProvidersServices[i]);
+
+ // Create consumer
+ properties = new Hashtable();
+ topics.put("donut-subscriber", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut consumer");
+
+ m_topicsConsumersInstances[i] = m_utils.getDonutConsumer2Factory()
+ .createComponentInstance(properties);
+ m_topicsConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .getService(m_topicsConsumersServices[i]);
+ topics.remove("donut-subscriber");
+ }
+
+ m_fooProvider = m_topicsProviders[0];
+ m_barProvider = m_topicsProviders[1];
+ m_nutProvider = m_topicsProviders[2];
+ m_fooBarProvider = m_topicsProviders[3];
+ m_barNutProvider = m_topicsProviders[4];
+ m_fooNutProvider = m_topicsProviders[5];
+ m_fooBarNutProvider = m_topicsProviders[6];
+ m_fooConsumer = m_topicsConsumers[0];
+ m_barConsumer = m_topicsConsumers[1];
+ m_nutConsumer = m_topicsConsumers[2];
+ m_fooBarConsumer = m_topicsConsumers[3];
+ m_barNutConsumer = m_topicsConsumers[4];
+ m_fooNutConsumer = m_topicsConsumers[5];
+ m_fooBarNutConsumer = m_topicsConsumers[6];
+
+ }
+
+ /**
+ * Creates a subscriber listening on a pattern topic (ending with '*').
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Dictionary properties = new Hashtable();
+ Dictionary topics = new Hashtable();
+
+ // Create the donut consumer instance, listening on a pattern topic
+ properties.put("instance.name", "subscriber with pattern topic");
+ topics.put("donut-subscriber", "a/pattern/topic/*");
+ properties.put("event.topics", topics);
+
+ ComponentInstance instance = m_utils.getDonutConsumer2Factory()
+ .createComponentInstance(properties);
+ instance.dispose();
+ }
+
+ /**
+ * Test the event handler reliability by sending events with all kinds of
+ * publisher and check they are received by all kinds of subscriber.
+ */
+ @Test
+ public void testReliability() {
+
+ // Flush donut list for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumers[i].clearDonuts();
+ }
+
+ // Send a lot of donut with each provider
+ List sentDonuts = new ArrayList(NUMBER_OF_PROVIDERS
+ * EahTestUtils.NUMBER_OF_TESTS);
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ sentDonuts.add(m_providers[i].sellDonut());
+ }
+ }
+
+ // Wait a respectable amount of time
+ EahTestUtils.sleep(EahTestUtils.BLACK_LIST_TIME
+ + EahTestUtils.A_LONG_TIME);
+
+ // Collect all received donuts for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ List receivedDonuts = Arrays.asList(m_consumers[i].getAllDonuts());
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts.",
+ sentDonuts.size(), receivedDonuts.size());
+ assertTrue("The receiver must have eaten all sent donuts.",
+ receivedDonuts.containsAll(sentDonuts));
+ }
+ }
+
+ /**
+ * Test the synchronism of event sending for the component.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ public void testSynchronism() {
+
+ // Flush donut list for quick consumers
+ for (int i = 0; i < NUMBER_OF_QUICK_CONSUMERS; i++) {
+ m_quickConsumers[i].clearDonuts();
+ }
+
+ // Send a lot of donuts and check they are immediately received.
+ Donut sentDonut;
+ Donut receivedDonut;
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ for (int j = 0; j < NUMBER_OF_SYNCHRONOUS_PROVIDERS; j++) {
+ sentDonut = m_synchronousProviders[j].sellDonut();
+ for (int k = 0; k < NUMBER_OF_QUICK_CONSUMERS; k++) {
+ receivedDonut = m_quickConsumers[k].getDonut();
+ assertEquals(
+ "The donut must have been received immediately and be the be the same as the sent one.",
+ sentDonut, receivedDonut);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test that the received events contains the instance name of the sender.
+ */
+ @Test
+ public void testInstanceName() {
+
+ // Flush event list of the event tracker
+ m_eventTracker.clearEvents();
+
+ // Send donuts and check the sender instance name
+ Event receivedEvent;
+ for (int i = 0; i < NUMBER_OF_EAH_PROVIDERS; i++) {
+ m_eahProviders[i].sellDonut();
+ receivedEvent = m_eventTracker.waitForEvent();
+ assertEquals(
+ "The instance name property of the received message must be the same as the sender instance name.",
+ m_eahProvidersInstances[i].getInstanceName(), receivedEvent
+ .getProperty("publisher.instance.name"));
+ }
+ }
+
+ /**
+ * Test the event filtering.
+ * <p/>
+ * This test send donuts with different flavours. Each filtered consumer
+ * must receive only a certain kind of donut. Of course, all donuts must
+ * have been received too.
+ */
+ @Test
+ public void testFilters() {
+
+ // The sent donuts, sorted by flavour
+ List[] sentDonuts = new List[Donut.FLAVOURS.length];
+
+ // Flush donut list for each filtered consumer
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ m_filteredConsumers[i].clearDonuts();
+ sentDonuts[i] = new ArrayList(EahTestUtils.NUMBER_OF_TESTS
+ / Donut.FLAVOURS.length);
+ }
+
+ // Send donuts
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ Donut donut = m_synchronousDonutEventProvider.sellDonut();
+ sentDonuts[EahTestUtils.flavourIndex(donut.getFlavour())]
+ .add(donut);
+ }
+
+ // Check the received donuts
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ Donut[] receivedDonuts = m_filteredConsumers[i].getAllDonuts();
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts with the matching flavour.",
+ sentDonuts[i].size(), receivedDonuts.length);
+ assertTrue(
+ "The receiver must have eaten all sent donuts matching the wanted flavour.",
+ Arrays.asList(receivedDonuts).containsAll(sentDonuts[i]));
+ }
+
+ }
+
+ /**
+ * Test the event topic.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ public void testTopics() {
+
+ // The sent donuts, sorted by topic
+ int foos = 0;
+ int bars = 0;
+ int nuts = 0;
+
+ // Flush consumers
+ m_fooConsumer.clearDonuts();
+ m_barConsumer.clearDonuts();
+ m_nutConsumer.clearDonuts();
+ m_fooBarConsumer.clearDonuts();
+ m_barNutConsumer.clearDonuts();
+ m_fooNutConsumer.clearDonuts();
+ m_fooBarNutConsumer.clearDonuts();
+
+ // Send donuts
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ m_fooProvider.sellDonut();
+ foos++;
+
+ m_barProvider.sellDonut();
+ bars++;
+
+ m_nutProvider.sellDonut();
+ nuts++;
+
+ m_fooBarProvider.sellDonut();
+ foos++;
+ bars++;
+
+ m_barNutProvider.sellDonut();
+ bars++;
+ nuts++;
+
+ m_fooNutProvider.sellDonut();
+ foos++;
+ nuts++;
+
+ m_fooBarNutProvider.sellDonut();
+ foos++;
+ bars++;
+ nuts++;
+ }
+
+ // Check received donuts
+ assertEquals("The number of received donuts must be correct.", foos,
+ m_fooConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars,
+ m_barConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", nuts,
+ m_nutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars, m_fooBarConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars
+ + nuts, m_barNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + nuts, m_fooNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars + nuts, m_fooBarNutConsumer.getAllDonuts().length);
+
+ }
+
+ /**
+ * Finalization after test cases.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java
new file mode 100644
index 0000000..2bb7a1e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java
@@ -0,0 +1,714 @@
+/*
+ * 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.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestPublisher extends Common {
+
+ /**
+ * The number of providers to test.
+ */
+ private static final int NUMBER_OF_PROVIDERS = 6;
+ /**
+ * The number of providers using the event admin handler to test.
+ */
+ private static final int NUMBER_OF_EAH_PROVIDERS = 4;
+ /**
+ * The number of consumers to test.
+ */
+ private static final int NUMBER_OF_CONSUMERS = 6;
+ /**
+ * The number of synchronous providers to test.
+ */
+ private static final int NUMBER_OF_SYNCHRONOUS_PROVIDERS = 3;
+ /**
+ * The number of slow consumers to test.
+ */
+ private static final int NUMBER_OF_QUICK_CONSUMERS = 3;
+ /**
+ * The list of topics to test.
+ */
+ private static final String[] TOPICS_LIST = {"foo", "bar", "nut",
+ "foo,bar", "bar,nut", "foo,nut", "foo,bar,nut"};
+ /**
+ * The utility class instance.
+ */
+ public EahTestUtils m_utils;
+ /**
+ * The providers' instances.
+ */
+ private ComponentInstance[] m_providersInstances;
+ /**
+ * The providers' service references.
+ */
+ private ServiceReference[] m_providersServices;
+ /**
+ * The providers' services.
+ */
+ private DonutProvider[] m_providers;
+ /**
+ * The synchronous providers' services.
+ */
+ private DonutProvider[] m_synchronousProviders;
+ /**
+ * The instances of providers that uses the event admin handler.
+ */
+ private ComponentInstance[] m_eahProvidersInstances;
+ /**
+ * The services of the providers that uses the event admin handler.
+ */
+ private DonutProvider[] m_eahProviders;
+ /**
+ * The synchronous donut event provider service.
+ */
+ private DonutProvider m_synchronousDonutEventProvider;
+ /**
+ * The consumers' instances.
+ */
+ private ComponentInstance[] m_consumersInstances;
+ /**
+ * The consumers' service references.
+ */
+ private ServiceReference[] m_consumersServices;
+ /**
+ * The consumers' services.
+ */
+ private DonutConsumer[] m_consumers;
+ /**
+ * The slow consumers' services.
+ */
+ private DonutConsumer[] m_quickConsumers;
+ /**
+ * The event tracker' instances.
+ */
+ private ComponentInstance m_eventTrackerInstance;
+ /**
+ * The event tracker' service references.
+ */
+ private ServiceReference m_eventTrackerService;
+ /**
+ * The event tracker service.
+ */
+ private EventTracker m_eventTracker;
+ /**
+ * The filtered consumers' instances.
+ */
+ private ComponentInstance[] m_filteredConsumersInstances;
+ /**
+ * The filtered consumers' service references.
+ */
+ private ServiceReference[] m_filteredConsumersServices;
+ /**
+ * The filtered consumers' services.
+ */
+ private DonutConsumer[] m_filteredConsumers;
+ /**
+ * The providers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsProvidersInstances;
+ /**
+ * The providers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsProvidersServices;
+ /**
+ * The providers' service with specified topics.
+ */
+ private DonutProvider[] m_topicsProviders;
+ /**
+ * The provider that send donuts on the "foo" topic.
+ */
+ private DonutProvider m_fooProvider;
+ /**
+ * The provider that send donuts on the "bar" topic.
+ */
+ private DonutProvider m_barProvider;
+ /**
+ * The provider that send donuts on the "nut" topic.
+ */
+ private DonutProvider m_nutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar" topics.
+ */
+ private DonutProvider m_fooBarProvider;
+ /**
+ * The provider that send donuts on the "bar,nut" topics.
+ */
+ private DonutProvider m_barNutProvider;
+ /**
+ * The provider that send donuts on the "foo,nut" topics.
+ */
+ private DonutProvider m_fooNutProvider;
+ /**
+ * The provider that send donuts on the "foo,bar,nut" topics.
+ */
+ private DonutProvider m_fooBarNutProvider;
+ /**
+ * The consumers' instances with specified topics.
+ */
+ private ComponentInstance[] m_topicsConsumersInstances;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private ServiceReference[] m_topicsConsumersServices;
+ /**
+ * The consumers' service references with specified topics.
+ */
+ private DonutConsumer[] m_topicsConsumers;
+ /**
+ * The consumer that receive donuts on the "foo" topic.
+ */
+ private DonutConsumer m_fooConsumer;
+ /**
+ * The consumer that receive donuts on the "bar" topic.
+ */
+ private DonutConsumer m_barConsumer;
+ /**
+ * The consumer that receive donuts on the "nut" topic.
+ */
+ private DonutConsumer m_nutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar" topics.
+ */
+ private DonutConsumer m_fooBarConsumer;
+ /**
+ * The consumer that receive donuts on the "bar,nut" topics.
+ */
+ private DonutConsumer m_barNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,nut" topics.
+ */
+ private DonutConsumer m_fooNutConsumer;
+ /**
+ * The consumer that receive donuts on the "foo,bar,nut" topics.
+ */
+ private DonutConsumer m_fooBarNutConsumer;
+
+ /**
+ * Initialization before test cases.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ Dictionary properties = new Hashtable();
+
+ // All the providers
+ m_providersInstances = new ComponentInstance[NUMBER_OF_PROVIDERS];
+ m_providersServices = new ServiceReference[NUMBER_OF_PROVIDERS];
+ m_providers = new DonutProvider[NUMBER_OF_PROVIDERS];
+ m_synchronousProviders = new DonutProvider[NUMBER_OF_SYNCHRONOUS_PROVIDERS];
+ m_eahProviders = new DonutProvider[NUMBER_OF_EAH_PROVIDERS];
+ m_eahProvidersInstances = new ComponentInstance[NUMBER_OF_EAH_PROVIDERS];
+ m_topicsProvidersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsProvidersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsProviders = new DonutProvider[TOPICS_LIST.length];
+
+ // Create the (asynchronous) donut provider
+ properties.put("instance.name", "asynchronous donut provider");
+ m_providersInstances[0] = m_utils.getDonutProviderUsingPublishesFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut provider");
+ m_providersInstances[1] = m_utils.getSynchronousDonutProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous donut event provider");
+ m_providersInstances[2] = m_utils.getDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous donut event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous donut event provider");
+ m_providersInstances[3] = m_utils
+ .getSynchronousDonutEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the (asynchronous) event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "asynchronous event provider");
+ m_providersInstances[4] = m_utils.getEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Create the synchronous event provider
+ properties = new Hashtable();
+ properties.put("instance.name", "synchronous event provider");
+ m_providersInstances[5] = m_utils.getSynchronousEventProviderFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ m_providersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .getService(m_providersServices[i]);
+ }
+ m_synchronousProviders[0] = m_providers[1];
+ m_synchronousProviders[1] = m_providers[3];
+ m_synchronousProviders[2] = m_providers[5];
+ m_eahProviders[0] = m_providers[0];
+ m_eahProviders[1] = m_providers[1];
+ m_eahProviders[2] = m_providers[2];
+ m_eahProviders[3] = m_providers[3];
+ m_eahProvidersInstances[0] = m_providersInstances[0];
+ m_eahProvidersInstances[1] = m_providersInstances[1];
+ m_eahProvidersInstances[2] = m_providersInstances[2];
+ m_eahProvidersInstances[3] = m_providersInstances[3];
+ m_synchronousDonutEventProvider = m_providers[3];
+
+ // All the consumers
+ m_consumersInstances = new ComponentInstance[NUMBER_OF_CONSUMERS];
+ m_consumersServices = new ServiceReference[NUMBER_OF_CONSUMERS];
+ m_consumers = new DonutConsumer[NUMBER_OF_CONSUMERS];
+ m_quickConsumers = new DonutConsumer[NUMBER_OF_QUICK_CONSUMERS];
+ m_filteredConsumersInstances = new ComponentInstance[Donut.FLAVOURS.length];
+ m_filteredConsumersServices = new ServiceReference[Donut.FLAVOURS.length];
+ m_filteredConsumers = new DonutConsumer[Donut.FLAVOURS.length];
+ m_topicsConsumersInstances = new ComponentInstance[TOPICS_LIST.length];
+ m_topicsConsumersServices = new ServiceReference[TOPICS_LIST.length];
+ m_topicsConsumers = new DonutConsumer[TOPICS_LIST.length];
+
+ // Create the (quick) donut consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut consumer");
+ m_consumersInstances[0] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick donut event consumer");
+ m_consumersInstances[1] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the (quick) event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "quick event consumer");
+ m_consumersInstances[2] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut consumer
+ properties = new Hashtable();
+ properties.put("slow", Boolean.TRUE);
+ properties.put("instance.name", "slow donut consumer");
+ m_consumersInstances[3] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow donut event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow donut event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[4] = m_utils.getDonutEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Create the slow event consumer
+ properties = new Hashtable();
+ properties.put("instance.name", "slow event consumer");
+ properties.put("slow", Boolean.TRUE);
+ m_consumersInstances[5] = m_utils.getEventConsumerFactory()
+ .createComponentInstance(properties);
+
+ // Get all the services references
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumersServices[i] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .getService(m_consumersServices[i]);
+ }
+ m_quickConsumers[0] = m_consumers[0];
+ m_quickConsumers[1] = m_consumers[1];
+ m_quickConsumers[2] = m_consumers[2];
+
+ // Create the event tracker
+ properties = new Hashtable();
+ properties.put("instance.name", "event tracker");
+ m_eventTrackerInstance = m_utils.getEventTrackerFactory()
+ .createComponentInstance(properties);
+ m_eventTrackerService = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .getService(m_eventTrackerService);
+
+ // Create the filtered consumer
+ Dictionary filter = new Hashtable();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ String flavour = Donut.FLAVOURS[i];
+ properties = new Hashtable();
+ filter.put("donut-event-subscriber", "(flavour=" + flavour + ")");
+ properties.put("instance.name", flavour + " donut consumer");
+ properties.put("event.filter", filter);
+ m_filteredConsumersInstances[i] = m_utils
+ .getDonutEventConsumerFactory().createComponentInstance(
+ properties);
+ m_filteredConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .getService(m_filteredConsumersServices[i]);
+ }
+
+ // Create the providers and consumers selling and receiving donuts on
+ // specific topics
+ Dictionary topics = new Hashtable();
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ String topicsString = TOPICS_LIST[i];
+ properties = new Hashtable();
+ // Create provider
+ topics.put("donut-publisher", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut provider");
+ m_topicsProvidersInstances[i] = m_utils
+ .getSynchronousDonutProviderFactory()
+ .createComponentInstance(properties);
+ m_topicsProvidersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .getService(m_topicsProvidersServices[i]);
+
+ // Create consumer
+ properties = new Hashtable();
+ topics.put("donut-subscriber", topicsString);
+ properties.put("event.topics", topics);
+ properties.put("instance.name", topicsString + " donut consumer");
+
+ m_topicsConsumersInstances[i] = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+ m_topicsConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .getService(m_topicsConsumersServices[i]);
+ topics.remove("donut-subscriber");
+ }
+
+ m_fooProvider = m_topicsProviders[0];
+ m_barProvider = m_topicsProviders[1];
+ m_nutProvider = m_topicsProviders[2];
+ m_fooBarProvider = m_topicsProviders[3];
+ m_barNutProvider = m_topicsProviders[4];
+ m_fooNutProvider = m_topicsProviders[5];
+ m_fooBarNutProvider = m_topicsProviders[6];
+ m_fooConsumer = m_topicsConsumers[0];
+ m_barConsumer = m_topicsConsumers[1];
+ m_nutConsumer = m_topicsConsumers[2];
+ m_fooBarConsumer = m_topicsConsumers[3];
+ m_barNutConsumer = m_topicsConsumers[4];
+ m_fooNutConsumer = m_topicsConsumers[5];
+ m_fooBarNutConsumer = m_topicsConsumers[6];
+
+ }
+
+ /**
+ * Creates a subscriber listening on a pattern topic (ending with '*').
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Dictionary properties = new Hashtable();
+ Dictionary topics = new Hashtable();
+
+ // Create the donut consumer instance, listening on a pattern topic
+ properties.put("instance.name", "subscriber with pattern topic");
+ topics.put("donut-subscriber", "a/pattern/topic/*");
+ properties.put("event.topics", topics);
+
+ ComponentInstance instance = m_utils.getDonutConsumerFactory()
+ .createComponentInstance(properties);
+ instance.dispose();
+ }
+
+ /**
+ * Test the event handler reliability by sending events with all kinds of
+ * publisher and check they are received by all kinds of subscriber.
+ */
+ @Test
+ public void testReliability() {
+
+ // Flush donut list for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ m_consumers[i].clearDonuts();
+ }
+
+ // Send a lot of donut with each provider
+ List sentDonuts = new ArrayList(NUMBER_OF_PROVIDERS
+ * EahTestUtils.NUMBER_OF_TESTS);
+ for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ sentDonuts.add(m_providers[i].sellDonut());
+ }
+ }
+
+ // Wait a respectable amount of time
+ EahTestUtils.sleep(EahTestUtils.BLACK_LIST_TIME
+ + EahTestUtils.A_LONG_TIME);
+
+ // Collect all received donuts for each consumer
+ for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+ List receivedDonuts = Arrays.asList(m_consumers[i].getAllDonuts());
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts.",
+ sentDonuts.size(), receivedDonuts.size());
+ assertTrue("The receiver must have eaten all sent donuts.",
+ receivedDonuts.containsAll(sentDonuts));
+ }
+ }
+
+ /**
+ * Test the synchronism of event sending for the component.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ public void testSynchronism() {
+
+ // Flush donut list for quick consumers
+ for (int i = 0; i < NUMBER_OF_QUICK_CONSUMERS; i++) {
+ m_quickConsumers[i].clearDonuts();
+ }
+
+ // Send a lot of donuts and check they are immediately received.
+ Donut sentDonut;
+ Donut receivedDonut;
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ for (int j = 0; j < NUMBER_OF_SYNCHRONOUS_PROVIDERS; j++) {
+ sentDonut = m_synchronousProviders[j].sellDonut();
+ for (int k = 0; k < NUMBER_OF_QUICK_CONSUMERS; k++) {
+ receivedDonut = m_quickConsumers[k].getDonut();
+ assertEquals(
+ "The donut must have been received immediately and be the be the same as the sent one.",
+ sentDonut, receivedDonut);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test that the received events contains the instance name of the sender.
+ */
+ @Test
+ public void testInstanceName() {
+
+ // Flush event list of the event tracker
+ m_eventTracker.clearEvents();
+
+ // Send donuts and check the sender instance name
+ Event receivedEvent;
+ for (int i = 0; i < NUMBER_OF_EAH_PROVIDERS; i++) {
+ m_eahProviders[i].sellDonut();
+ receivedEvent = m_eventTracker.waitForEvent();
+ assertEquals(
+ "The instance name property of the received message must be the same as the sender instance name.",
+ m_eahProvidersInstances[i].getInstanceName(), receivedEvent
+ .getProperty("publisher.instance.name"));
+ }
+ }
+
+ /**
+ * Test the event filtering.
+ * <p/>
+ * This test send donuts with different flavours. Each filtered consumer
+ * must receive only a certain kind of donut. Of course, all donuts must
+ * have been received too.
+ */
+ @Test
+ public void testFilters() {
+
+ // The sent donuts, sorted by flavour
+ List[] sentDonuts = new List[Donut.FLAVOURS.length];
+
+ // Flush donut list for each filtered consumer
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ m_filteredConsumers[i].clearDonuts();
+ sentDonuts[i] = new ArrayList(EahTestUtils.NUMBER_OF_TESTS
+ / Donut.FLAVOURS.length);
+ }
+
+ // Send donuts
+ for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+ Donut donut = m_synchronousDonutEventProvider.sellDonut();
+ sentDonuts[EahTestUtils.flavourIndex(donut.getFlavour())]
+ .add(donut);
+ }
+
+ // Check the received donuts
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ Donut[] receivedDonuts = m_filteredConsumers[i].getAllDonuts();
+ assertEquals(
+ "The number of received donuts must be the same as the number of sent donuts with the matching flavour.",
+ sentDonuts[i].size(), receivedDonuts.length);
+ assertTrue(
+ "The receiver must have eaten all sent donuts matching the wanted flavour.",
+ Arrays.asList(receivedDonuts).containsAll(sentDonuts[i]));
+ }
+
+ }
+
+ /**
+ * Test the event topic.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ public void testTopics() {
+
+ // The sent donuts, sorted by topic
+ int foos = 0;
+ int bars = 0;
+ int nuts = 0;
+
+ // Flush consumers
+ m_fooConsumer.clearDonuts();
+ m_barConsumer.clearDonuts();
+ m_nutConsumer.clearDonuts();
+ m_fooBarConsumer.clearDonuts();
+ m_barNutConsumer.clearDonuts();
+ m_fooNutConsumer.clearDonuts();
+ m_fooBarNutConsumer.clearDonuts();
+
+ // Send donuts
+ for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+ m_fooProvider.sellDonut();
+ foos++;
+
+ m_barProvider.sellDonut();
+ bars++;
+
+ m_nutProvider.sellDonut();
+ nuts++;
+
+ m_fooBarProvider.sellDonut();
+ foos++;
+ bars++;
+
+ m_barNutProvider.sellDonut();
+ bars++;
+ nuts++;
+
+ m_fooNutProvider.sellDonut();
+ foos++;
+ nuts++;
+
+ m_fooBarNutProvider.sellDonut();
+ foos++;
+ bars++;
+ nuts++;
+ }
+
+ // Check received donuts
+ assertEquals("The number of received donuts must be correct.", foos,
+ m_fooConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars,
+ m_barConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", nuts,
+ m_nutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars, m_fooBarConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", bars
+ + nuts, m_barNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + nuts, m_fooNutConsumer.getAllDonuts().length);
+ assertEquals("The number of received donuts must be correct.", foos
+ + bars + nuts, m_fooBarNutConsumer.getAllDonuts().length);
+
+ }
+
+ /**
+ * Finalization after test cases.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/eventadmin/eventadmin-handler-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/changelog.txt b/ipojo/handler/eventadmin/eventadmin-handler/changelog.txt
new file mode 100644
index 0000000..dec3825
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/changelog.txt
@@ -0,0 +1,32 @@
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2718] - EventHandler are invoked one by one when using the @Subscribe handler
+
+** Improvement
+ * [FELIX-2631] - Rename @Publisher and @Subscriber attributes to follow the java naming conventions
+ * [FELIX-2634] - Rename the @Publisher annotation into @Publishes annotation to avoid collision
+ * [FELIX-2711] - The event admin handler should provides a Handler Description
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1938] - Bad error message when an Event Subscriber does not set the data type and data key
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+
+ Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-794] - Event Admin handler reject correctly formed topics
+
+** Improvement
+ * [FELIX-795] - Improve metadata and manipulator performance
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+Version 1.0.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/metadata.xml b/ipojo/handler/eventadmin/eventadmin-handler/metadata.xml
new file mode 100644
index 0000000..69b340b
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/metadata.xml
@@ -0,0 +1,41 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.event.subscriber.EventAdminSubscriberHandler"
+ name="subscriber"
+ namespace="org.apache.felix.ipojo.handlers.event">
+ <provides>
+ <property field="m_topics" name="event.topics"/>
+ </provides>
+ </handler>
+
+ <!-- This handler is duplicated to support the 'Publishes' annotation -->
+ <handler classname="org.apache.felix.ipojo.handlers.event.publisher.EventAdminPublisherHandler"
+ name="publisher"
+ namespace="org.apache.felix.ipojo.handlers.event">
+ <requires field="m_ea"/>
+ </handler>
+
+ <handler classname="org.apache.felix.ipojo.handlers.event.publisher.EventAdminPublisherHandler"
+ name="publishes"
+ namespace="org.apache.felix.ipojo.handlers.event">
+ <requires field="m_ea"/>
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/obr.xml b/ipojo/handler/eventadmin/eventadmin-handler/obr.xml
new file mode 100644
index 0000000..4e53bb3
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/obr.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="publisher"/>
+ <p n="namespace" v="org.apache.felix.ipojo.handlers.event"/>
+ <p n="type" v="primitive"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="subscriber"/>
+ <p n="namespace" v="org.apache.felix.ipojo.handlers.event"/>
+ <p n="type" v="primitive"/>
+ </capability>
+ <require extend="false" filter="(service=org.osgi.service.event.EventAdmin)" multiple="false" name="service" optional="false">Import Event Admin service</require>
+</obr>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/pom.xml b/ipojo/handler/eventadmin/eventadmin-handler/pom.xml
new file mode 100644
index 0000000..873e87d
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/pom.xml
@@ -0,0 +1,113 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Event Admin Handler</name>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+
+ <description>
+ iPOJO extension to easily interact with the OSGi Event Admin.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/event-admin-handlers.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>org.apache.felix.ipojo.handlers.event*;version="1.2.0"</Export-Package>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Description>iPOJO Event Admin Handlers
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/event-admin-handlers.html
+ </Bundle-DocURL>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.10.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <metadata>metadata.xml</metadata>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java
new file mode 100644
index 0000000..c46dacf
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java
@@ -0,0 +1,173 @@
+/*
+ * 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.handlers.event;
+
+import org.apache.felix.ipojo.parser.ParseUtils;
+
+/**
+ * Utility methods.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventUtil {
+
+ /**
+ * The separator between topics.
+ */
+ public static final String TOPIC_SEPARATOR = ",";
+
+ /**
+ * The separator between topics.
+ */
+ public static final String TOPIC_TOKEN_SEPARATOR = "/";
+
+ /**
+ * The topic token alphabet.
+ */
+ private static final String TOKEN_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
+
+ /**
+ * Tests that the given topic match with the given topic pattern.
+ *
+ * @param topic the topic to test
+ * @param topicPattern the topic pattern
+ * @return true if it matches.
+ */
+ public static final boolean matches(String topic, String topicPattern) {
+ if (topicPattern.equals("*")) {
+ return true;
+ }
+ int star;
+ if ((star = topicPattern.indexOf("*")) > 0) {
+ return topic.startsWith(topicPattern.substring(0, star - 1));
+ } else {
+ return topic.equals(topicPattern);
+ }
+ }
+
+ /**
+ * Tests that the given topic match with the given topic patterns.
+ *
+ * @param topic the topic to test
+ * @param topicPatterns the topic patterns
+ * @return true if it matches.
+ */
+ public static final boolean matches(String topic, String[] topicPatterns) {
+ int n = topicPatterns.length;
+ for (int i = 0; i < n; i++) {
+ if (matches(topic, topicPatterns[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check the given topic scope is valid.
+ *
+ * topicScope ::= "*" | ( topic "/*" ? )
+ *
+ * @param topicScope the topic scope to check.
+ *
+ * @return {@code true} if the given topic scope is valid, {@code false}
+ * otherwise.
+ */
+ public static final boolean isValidTopicScope(String topicScope) {
+ if (topicScope.equals("*")) {
+ // Wildcard character only accepted.
+ return true;
+ }
+
+ // Remove trailing "/*" if present, to check the topic radix.
+ String topicWithoutWildcard;
+ if (topicScope.endsWith("/*")) {
+ topicWithoutWildcard = topicScope.substring(0,
+ topicScope.length() - 2);
+ } else {
+ topicWithoutWildcard = topicScope;
+ }
+
+ // Validate the topic radix.
+ return isValidTopic(topicWithoutWildcard);
+ }
+
+ /**
+ * Check the given topic is valid.
+ *
+ * topic ::= token ( �/� token ) *
+ *
+ * @param topic the topic to check.
+ *
+ * @return {@code true} if the given topic is valid, {@code false}
+ * otherwise.
+ */
+ public static final boolean isValidTopic(String topic) {
+ if (topic.startsWith(TOPIC_TOKEN_SEPARATOR)
+ || topic.endsWith(TOPIC_TOKEN_SEPARATOR)) {
+ // A topic cannot start nor end with '/'.
+ return false;
+ }
+
+ String[] tokens = ParseUtils.split(topic, TOPIC_TOKEN_SEPARATOR);
+ if (tokens.length < 1) {
+ // A topic must contain at least one token.
+ return false;
+ }
+
+ // Check each token is valid.
+ for (int i = 0; i < tokens.length; i++) {
+ String token = tokens[i];
+ if (!isValidToken(token)) {
+ return false;
+ }
+ }
+
+ // The topic is valid.
+ return true;
+ }
+
+ /**
+ * Check the given token is valid.
+ *
+ * token ::= ( alphanum | "_" | "-" )+
+ *
+ * @param token the token to check.
+ *
+ * @return {@code true} if the given topic token is valid, {@code false}
+ * otherwise.
+ */
+ private static boolean isValidToken(String token) {
+ int length = token.length();
+ if (length < 1) {
+ // Token must contain at least one character.
+ return false;
+ }
+
+ for (int i = 0; i < length; i++) {
+ // Each character in the token must belong to the token alphabet.
+ if (TOKEN_ALPHABET.indexOf(token.charAt(i)) == -1) {
+ return false;
+ }
+ }
+
+ // The token is valid.
+ return true;
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java
new file mode 100644
index 0000000..1629726
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java
@@ -0,0 +1,282 @@
+/*
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * Event Publisher Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminPublisherHandler extends PrimitiveHandler {
+
+ /**
+ * The handler Namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event";
+
+ /**
+ * The names of instance configuration properties.
+ */
+ public static final String TOPICS_PROPERTY = "event.topics";
+
+ /**
+ * The prefix for logged messages.
+ */
+ private static final String LOG_PREFIX = "EVENT ADMIN PUBLISHER HANDLER : ";
+
+ /**
+ * The instance manager.
+ */
+ private InstanceManager m_manager;
+
+ /**
+ * The current EventAdmin service.
+ */
+ private EventAdmin m_ea;
+
+ /**
+ * The publishers accessible by their fields.
+ */
+ private Map m_publishersByField = new Hashtable();
+
+ /**
+ * The handler description
+ */
+ private EventAdminPublisherHandlerDescription m_description;
+
+ /**
+ * Initializes the component type.
+ *
+ * @param cd the component type description to populate
+ * @param metadata the component type metadata
+ * @throws ConfigurationException if the given metadata is incorrect.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(
+ * org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription cd,
+ Element metadata)
+ throws ConfigurationException {
+
+ // Update the current component description
+ Dictionary dict = new Properties();
+ PropertyDescription pd = new PropertyDescription(TOPICS_PROPERTY,
+ Dictionary.class.getName(), dict.toString());
+ cd.addProperty(pd);
+
+ // Get Metadata publishers
+ Element[] publishers = metadata.getElements("publisher", NAMESPACE);
+
+ // if publisher is null, look for 'publishes' elements
+ if (publishers == null || publishers.length == 0) {
+ publishers = metadata.getElements("publishes", NAMESPACE);
+ }
+
+ if (publishers != null) {
+
+ // Maps used to check name and field are unique
+ Set nameSet = new HashSet();
+ Set fieldSet = new HashSet();
+
+ // Check all publishers are well formed
+ for (int i = 0; i < publishers.length; i++) {
+
+ // Check the publisher configuration is correct by creating an
+ // unused publisher metadata
+ EventAdminPublisherMetadata publisherMetadata = new EventAdminPublisherMetadata(
+ publishers[i]);
+ String name = publisherMetadata.getName();
+ info(LOG_PREFIX + "Checking publisher " + name);
+
+ // Check field existence and type
+ String field = publisherMetadata.getField();
+ FieldMetadata fieldMetadata = getPojoMetadata()
+ .getField(publisherMetadata.getField(),
+ Publisher.class.getName());
+ if (fieldMetadata == null) {
+ throw new ConfigurationException(
+ "Field not found in the component : "
+ + Publisher.class.getName() + " " + field);
+ }
+
+ // Check name and field are unique
+ if (nameSet.contains(name)) {
+ throw new ConfigurationException(
+ "A publisher with the same name already exists : "
+ + name);
+ } else if (fieldSet.contains(field)) {
+ throw new ConfigurationException("The field " + field
+ + " is already associated to a publisher");
+ }
+ nameSet.add(name);
+ fieldSet.add(field);
+ }
+ } else {
+ info(LOG_PREFIX + "No publisher to check");
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param metadata the component type metadata
+ * @param conf the instance configuration
+ * @throws ConfigurationException if one event publication is not correct
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary conf)
+ throws ConfigurationException {
+
+ // Store the component manager
+ m_manager = getInstanceManager();
+
+ // Get the topics instance configuration
+ Dictionary instanceTopics = (Dictionary) conf.get(TOPICS_PROPERTY);
+
+ // Get Metadata publishers
+ Element[] publishers = metadata.getElements("publisher", NAMESPACE);
+
+ // if publisher is null, look for 'publishes' elements
+ if (publishers == null || publishers.length == 0) {
+ publishers = metadata.getElements("publishes", NAMESPACE);
+ }
+
+ if (publishers != null) {
+ // then check publishers are well formed and fill the publishers'
+ // map
+ for (int i = 0; i < publishers.length; i++) {
+
+ // Extract the publisher configuration
+ EventAdminPublisherMetadata publisherMetadata = new EventAdminPublisherMetadata(
+ publishers[i]);
+ String name = publisherMetadata.getName();
+ info(LOG_PREFIX + "Configuring publisher " + name);
+
+ // Get the topic instance configuration if redefined
+ String topicsString = (instanceTopics != null) ? (String) instanceTopics
+ .get(name)
+ : null;
+ if (topicsString != null) {
+ publisherMetadata.setTopics(topicsString);
+ }
+
+ // Check the publisher is correctly configured
+ publisherMetadata.check();
+
+ // Create the associated Publisher and insert it in the
+ // publisher map
+ Publisher publisher = new PublisherImpl(this, publisherMetadata
+ .getTopics(), publisherMetadata.isSynchronous(),
+ publisherMetadata.getDataKey(), m_manager
+ .getInstanceName());
+ m_publishersByField
+ .put(publisherMetadata.getField(), publisher);
+
+ // Register the callback that return the publisher
+ // reference when the specified field is read by the
+ // POJO.
+ FieldMetadata fieldMetadata = getPojoMetadata()
+ .getField(publisherMetadata.getField(),
+ Publisher.class.getName());
+ m_manager.register(fieldMetadata, this);
+
+ }
+ } else {
+ info(LOG_PREFIX + "No publisher to configure");
+ }
+
+ setValidity(true);
+
+ debug(LOG_PREFIX+ "Setup description....");
+ m_description = new EventAdminPublisherHandlerDescription(this, m_publishersByField.values()); // Initialize the description.
+
+ }
+
+ /**
+ * Starts the handler instance.
+ *
+ * This method does nothing.
+ */
+ public void start() {
+ }
+
+ /**
+ * Stops the handler instance.
+ *
+ * This method does nothing.
+ */
+ public void stop() {
+ }
+
+ /**
+ * Field interceptor callback. This method is called when the component
+ * attempt to one of its Publisher field.
+ *
+ * @param pojo the accessed field
+ * @param fieldName the name of the accessed field
+ * @param value the value of the field (useless here)
+ *
+ * @return the Publisher associated with the accessed field's name
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+ // Retrieve the publisher associated to the given field name
+ Publisher pub = (Publisher) m_publishersByField.get(fieldName);
+ if (pub == null) {
+ error(LOG_PREFIX + "No publisher associated to the field "
+ + fieldName);
+ }
+ return pub;
+ }
+
+ /**
+ * This method is called by managed publishers to obtain the current
+ * EventAdmin service.
+ *
+ * @return the current EventAdmin service.
+ */
+ public EventAdmin getEventAdminService() {
+ return m_ea;
+ }
+
+ /**
+ * Gets the handler description
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandlerDescription.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandlerDescription.java
new file mode 100644
index 0000000..3069766
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandlerDescription.java
@@ -0,0 +1,102 @@
+/*
+ * 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.handlers.event.publisher;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Handler Description for Event Admin Publisher.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminPublisherHandlerDescription extends HandlerDescription {
+
+ /**
+ * The list of publishers.
+ */
+ List/*<PublisherDescription>*/ m_publishersDescriptions;
+
+ // FIXME : Add listener interface for
+ // : onServiceArrival, onServiceDeparture, onServiceBound, onServiceUnbound
+ // : methods.
+
+ /**
+ * Creates the {@link EventAdminPublisherHandlerDescription}.
+ * @param handler the handler
+ * @param publishers the list of publishers
+ */
+ public EventAdminPublisherHandlerDescription(Handler handler, Collection/*<Publisher>*/ publishers) {
+ super(handler);
+
+ m_publishersDescriptions = new ArrayList/*<PublisherDescription>*/();
+ if (publishers != null) {
+ Iterator iterator = publishers.iterator();
+ while (iterator.hasNext()){
+ Publisher p = (Publisher) iterator.next();
+ m_publishersDescriptions.add(new PublisherDescription(p));
+ }
+ }
+
+ }
+
+ /**
+ * Gets the publisher descriptions.
+ * @return the descriptions.
+ */
+ public PublisherDescription[] getPublisherDescriptions() {
+ return (PublisherDescription[])
+ m_publishersDescriptions.toArray(new PublisherDescription[m_publishersDescriptions.size()]);
+ }
+
+ /**
+ * Gets the handler description.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element root = super.getHandlerInfo();
+ for (int i = 0; i < m_publishersDescriptions.size(); i++) {
+ PublisherDescription p = (PublisherDescription) m_publishersDescriptions.get(i);
+ Element publisher = new Element("Publisher", "");
+ publisher.addAttribute(new Attribute("name", p.getName()));
+ publisher.addAttribute(new Attribute("synchronous", String.valueOf(p.isSynchronous())));
+ publisher.addAttribute(new Attribute("data_key", p.getDataKey()));
+ Element topics = new Element("Topics", "");
+ if (p.getTopics() != null) {
+ for (int j = 0; j < p.getTopics().length; j++) {
+ String topic = p.getTopics()[j];
+ Element e_topic = new Element("topic","");
+ topics.addElement(e_topic);
+ e_topic.addAttribute(new Attribute("name",topic));
+ }
+ }
+ publisher.addElement(topics);
+ root.addElement(publisher);
+ }
+ return root;
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java
new file mode 100644
index 0000000..224117e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java
@@ -0,0 +1,242 @@
+/*
+ * 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.handlers.event.publisher;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.handlers.event.EventUtil;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+
+/**
+ * Represent a publisher.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+class EventAdminPublisherMetadata {
+
+ // Names of metadata attributes
+
+ /**
+ * The name attribute in the component metadata.
+ */
+ public static final String NAME_ATTRIBUTE = "name";
+
+ /**
+ * The field attribute in the component metadata.
+ */
+ public static final String FIELD_ATTRIBUTE = "field";
+
+ /**
+ * The topics attribute in the component metadata.
+ */
+ public static final String TOPICS_ATTRIBUTE = "topics";
+
+ /**
+ * The synchronous attribute in the component metadata.
+ */
+ public static final String SYNCHRONOUS_ATTRIBUTE = "synchronous";
+
+ /**
+ * The data key attribute in the component metadata.
+ */
+ public static final String DATA_KEY_ATTRIBUTE = "data-key";
+
+ // Default values
+
+ /**
+ * The data key attribute's default value.
+ */
+ public static final String DEFAULT_DATA_KEY_VALUE = "user.data";
+
+ /**
+ * The synchronous attribute's default value.
+ */
+ public static final boolean DEFAULT_SYNCHRONOUS_VALUE = false;
+
+ /**
+ * The name which acts as an identifier.
+ */
+ private final String m_name;
+
+ /**
+ * The name of the field representing the publisher in the component.
+ */
+ private final String m_field;
+
+ /**
+ * Topics to which events are sent.
+ */
+ private String[] m_topics;
+
+ /**
+ * Events sending mode.
+ */
+ private final boolean m_synchronous;
+
+ /**
+ * The key where user data are stored in the event dictionary.
+ */
+ private final String m_dataKey;
+
+ /**
+ * Constructs a publisher from its metadata description.
+ *
+ * @param publisher the publisher metadata description.
+ * @throws ConfigurationException if the configuration of the component or
+ * the instance is invalid.
+ */
+ public EventAdminPublisherMetadata(Element publisher)
+ throws ConfigurationException {
+
+ /**
+ * Setup required attributes
+ */
+
+ // NAME_ATTRIBUTE
+ if (publisher.containsAttribute(NAME_ATTRIBUTE)) {
+ m_name = publisher.getAttribute(NAME_ATTRIBUTE);
+ } else {
+ throw new ConfigurationException(
+ "Missing required attribute in component configuration : "
+ + NAME_ATTRIBUTE);
+ }
+
+ // FIELD_ATTRIBUTE
+ if (publisher.containsAttribute(FIELD_ATTRIBUTE)) {
+ m_field = publisher.getAttribute(FIELD_ATTRIBUTE);
+ } else {
+ throw new ConfigurationException(
+ "Missing required attribute in component configuration : "
+ + FIELD_ATTRIBUTE);
+ }
+
+ // TOPICS_ATTRIBUTE
+ if (publisher.containsAttribute(TOPICS_ATTRIBUTE)) {
+ setTopics(publisher.getAttribute(TOPICS_ATTRIBUTE));
+ } else {
+ m_topics = null;
+ // Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+ // overridden in the instance configuration.
+ }
+
+ /**
+ * Setup optional attributes
+ */
+
+ // SYNCHRONOUS_ATTRIBUTE
+ if (publisher.containsAttribute(SYNCHRONOUS_ATTRIBUTE)) {
+ m_synchronous = "true".equalsIgnoreCase(publisher
+ .getAttribute(SYNCHRONOUS_ATTRIBUTE));
+ } else {
+ m_synchronous = DEFAULT_SYNCHRONOUS_VALUE;
+ }
+
+ // DATA_KEY_ATTRIBUTE
+ if (publisher.containsAttribute(DATA_KEY_ATTRIBUTE)) {
+ m_dataKey = publisher.getAttribute(DATA_KEY_ATTRIBUTE);
+ } else if (publisher.containsAttribute("data_key")) {
+ // XML Case
+ m_dataKey = publisher.getAttribute("data_key");
+ } else if (publisher.containsAttribute("dataKey")) {
+ // Annotation case.
+ m_dataKey = publisher.getAttribute("dataKey");
+ } else {
+ m_dataKey = DEFAULT_DATA_KEY_VALUE;
+ }
+ }
+
+ /**
+ * Sets the topics attribute of the publisher.
+ *
+ * @param topicsString the comma separated list of the topics on which
+ * events are sent
+ * @throws ConfigurationException the specified topic string is malformed
+ */
+ public void setTopics(String topicsString) throws ConfigurationException {
+ String[] newTopics = ParseUtils.split(topicsString,
+ EventUtil.TOPIC_SEPARATOR);
+ // Check each topic is valid
+ for (int i = 0; i < newTopics.length; i++) {
+ String topic = newTopics[i];
+ if (!EventUtil.isValidTopic(topic)) {
+ throw new ConfigurationException("Invalid topic : \"" + topic
+ + "\".");
+ }
+ }
+ m_topics = newTopics;
+ }
+
+ /**
+ * Checks that the required instance configurable attributes are all set.
+ *
+ * @throws ConfigurationException if a required attribute is missing
+ */
+ public void check() throws ConfigurationException {
+ if (m_topics == null || m_topics.length == 0) {
+ throw new ConfigurationException(
+ "Missing required attribute in component or instance configuration : "
+ + TOPICS_ATTRIBUTE);
+ }
+ }
+
+ /**
+ * Gets the name attribute of the publisher.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets the field attribute of the publisher.
+ *
+ * @return the field
+ */
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * Gets the topics attribute of the publisher.
+ *
+ * @return the topics
+ */
+ public String[] getTopics() {
+ return m_topics;
+ }
+
+ /**
+ * Gets the synchronous attribute of the publisher.
+ *
+ * @return the synchronous mode
+ */
+ public boolean isSynchronous() {
+ return m_synchronous;
+ }
+
+ /**
+ * Gets the dataKey attribute of the publisher.
+ *
+ * @return the data key
+ */
+ public String getDataKey() {
+ return m_dataKey;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/Publisher.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/Publisher.java
new file mode 100644
index 0000000..7b25196
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/Publisher.java
@@ -0,0 +1,70 @@
+/*
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+
+/**
+ * An Publisher is the interface between the EventAdminPublisherHandler and a
+ * component instance. The POJO can send event through the handler by calling a
+ * {@code send} method.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Publisher {
+
+ /**
+ * Sends an event with the specified content.
+ *
+ * @param content the content of the event
+ */
+ void send(Dictionary content);
+
+ /**
+ * Sends a data event.
+ *
+ * @param o the data to send
+ */
+ void sendData(Object o);
+
+ /**
+ * Gets the published topics.
+ * @return the list of topics.
+ */
+ String[] getTopics();
+
+ /**
+ * Checks is the publisher send data synchronously.
+ * @return <code>true</code> if the publisher is synchronous.
+ */
+ boolean isSynchronous();
+
+ /**
+ * Gets the data key if used.
+ * @return the data key or <code>null</code>
+ */
+ String getDataKey();
+
+ /**
+ * Gets the publisher name if any.
+ * @return the publisher name
+ */
+ String getName();
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherDescription.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherDescription.java
new file mode 100644
index 0000000..c25f37b
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherDescription.java
@@ -0,0 +1,76 @@
+/*
+ * 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.handlers.event.publisher;
+
+/**
+ * Publisher Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PublisherDescription {
+
+ /**
+ * The described publisher
+ */
+ private Publisher m_publisher;
+
+ /**
+ * Creates a {@link PublisherDescription} based
+ * on the given {@link Publisher}
+ * @param p the publisher
+ */
+ public PublisherDescription(Publisher p) {
+ m_publisher = p;
+ }
+
+
+ /**
+ * Gets the topic list.
+ * @return the list of published topics
+ */
+ public String[] getTopics() {
+ return m_publisher.getTopics();
+ }
+
+ /**
+ * Checks if the publisher is synchronous.
+ * @return <code>true</code> if the publisher is synchronous
+ */
+ public boolean isSynchronous() {
+ return m_publisher.isSynchronous();
+ }
+
+ /**
+ * Gets the data key if used.
+ * @return the data key
+ */
+ public String getDataKey() {
+ return m_publisher.getDataKey();
+ }
+
+ /**
+ * Gets the publisher name if any.
+ * @return the publisher name
+ */
+ public String getName() {
+ return m_publisher.getName();
+ }
+
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java
new file mode 100644
index 0000000..1cdcc89
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java
@@ -0,0 +1,145 @@
+/*
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.service.event.Event;
+
+/**
+ * The PublisherImpl class is the implementation of the Publisher object used by
+ * components to send events.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PublisherImpl implements Publisher {
+
+ /**
+ * The key where the component instance name is stored.
+ */
+ public static final String INSTANCE_NAME_PROPERTY = "publisher.instance.name";
+
+ /**
+ * The managing handler.
+ */
+ private EventAdminPublisherHandler m_handler;
+
+ /**
+ * The topics of sent events.
+ */
+ private final String[] m_topics;
+
+ /**
+ * The sending mode of events.
+ */
+ private final boolean m_synchronous;
+
+ /**
+ * The key, in the content of the event, where user data are stored.
+ */
+ private final String m_dataKey;
+
+ /**
+ * The name of the component instance using this publisher.
+ */
+ private final String m_instanceName;
+
+ /**
+ * Constructs an Publisher with given parameters.
+ *
+ * @param handler the handler that will manage this publisher
+ * @param topics the topics on which events are sent
+ * @param synchronous the sending mode of events
+ * @param dataKey The key, in the content of the event, where user data are
+ * stored (may be {@code null})
+ * @param instanceName the name of the instance creating this publisher.
+ */
+ public PublisherImpl(EventAdminPublisherHandler handler, String[] topics,
+ boolean synchronous, String dataKey, String instanceName) {
+
+ // Initialize the publisher's fields
+ m_handler = handler;
+ m_topics = topics;
+ m_synchronous = synchronous;
+ m_dataKey = dataKey;
+ m_instanceName = instanceName;
+ }
+
+ /**
+ * Sends an event with the specified content.
+ *
+ * @param content the content of the event
+ */
+ public void send(Dictionary content) {
+ // Add instance information in the event
+ content.put(INSTANCE_NAME_PROPERTY, m_instanceName);
+ // We sent the event on each topic
+ for (int i = 0; i < m_topics.length; i++) {
+ // Create an event with the given topic and content
+ Event e = new Event(m_topics[i], content);
+ // Send the event, depending on the sending mode
+ if (!m_synchronous) {
+ m_handler.getEventAdminService().postEvent(e); // Asynchronous
+ } else {
+ m_handler.getEventAdminService().sendEvent(e); // Synchronous
+ }
+ }
+ }
+
+ /**
+ * Sends a data event.
+ *
+ * @param object the data to send
+ */
+ public void sendData(Object object) {
+ // Construct the content of the event with the given object
+ Dictionary content = new Hashtable();
+ content.put(m_dataKey, object);
+ send(content);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.handlers.event.publisher.Publisher#getTopics()
+ */
+ public String[] getTopics() {
+ return m_topics;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.handlers.event.publisher.Publisher#isSynchronous()
+ */
+ public boolean isSynchronous() {
+ return m_synchronous;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.handlers.event.publisher.Publisher#getDataKey()
+ */
+ public String getDataKey() {
+ return m_dataKey;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.handlers.event.publisher.Publisher#getName()
+ */
+ public String getName() {
+ return m_instanceName;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java
new file mode 100644
index 0000000..edbd7a3
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java
@@ -0,0 +1,421 @@
+/*
+ * 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.handlers.event.subscriber;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.event.EventUtil;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.osgi.framework.Filter;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+/**
+ * Event Subscriber Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminSubscriberHandler extends PrimitiveHandler implements
+ EventHandler {
+
+ /**
+ * The handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event";
+
+ // Names of instance configuration properties.
+
+ /**
+ * The event's topics instance configuration property.
+ */
+ public static final String TOPICS_PROPERTY = "event.topics";
+
+ /**
+ * The event's filter instance configuration property.
+ */
+ public static final String FILTER_PROPERTY = "event.filter";
+
+ /**
+ * The prefix for logged messages.
+ */
+ private static final String LOG_PREFIX = "EVENT ADMIN SUBSCRIBER HANDLER : ";
+
+ /**
+ * The instance manager.
+ */
+ private InstanceManager m_manager;
+
+ /**
+ * The list of subscriber accessible by name.
+ */
+ private final Map m_subscribersByName = new HashMap();
+
+ /**
+ * The list of callbacks accessible by subscribers' names.
+ */
+ private final Map m_callbacksByName = new Hashtable();
+
+ /**
+ * The iPOJO properties representing all the topics.
+ * Immutable.
+ */
+ private String[] m_topics;
+
+ /**
+ * Listening to received events ?
+ */
+ private boolean m_isListening;
+
+ /**
+ * The handler description
+ */
+ private EventAdminSubscriberHandlerDescription m_description;
+
+ /**
+ * Initializes the component type.
+ *
+ * @param cd component type description to populate.
+ * @param metadata component type metadata.
+ * @throws ConfigurationException if the metadata are incorrect.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(
+ * org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription cd,
+ Element metadata)
+ throws ConfigurationException {
+
+ // Update the current component description
+ Dictionary dict = new Properties();
+ cd.addProperty(new PropertyDescription(TOPICS_PROPERTY,
+ Dictionary.class.getName(), dict.toString()));
+ dict = new Properties();
+ cd.addProperty(new PropertyDescription(FILTER_PROPERTY,
+ Dictionary.class.getName(), dict.toString()));
+
+ // Get Metadata subscribers
+ Element[] subscribers = metadata.getElements("subscriber", NAMESPACE);
+ if (subscribers != null) {
+
+ // Maps used to check name and field are unique
+ Set nameSet = new HashSet();
+ Set callbackSet = new HashSet();
+
+ // Check all subscribers are well formed
+ for (int i = 0; i < subscribers.length; i++) {
+
+ // Check the subscriber configuration is correct by creating an
+ // unused subscriber metadata
+ EventAdminSubscriberMetadata subscriberMetadata = new EventAdminSubscriberMetadata(
+ getFactory().getBundleContext(), subscribers[i]);
+
+ String name = subscriberMetadata.getName();
+ info(LOG_PREFIX + "Checking subscriber " + name);
+
+ // Determine the event callback prototype
+ PojoMetadata pojoMetadata = getPojoMetadata();
+ String callbackType;
+ if (subscriberMetadata.getDataKey() == null) {
+ callbackType = Event.class.getName();
+ } else {
+ callbackType = subscriberMetadata.getDataType().getName();
+ }
+
+ // Check the event callback method is present
+ MethodMetadata methodMetadata = pojoMetadata.getMethod(
+ subscriberMetadata.getCallback(),
+ new String[] { callbackType });
+ String callbackSignature = subscriberMetadata.getCallback()
+ + "(" + callbackType + ")";
+ if (methodMetadata == null) {
+ throw new ConfigurationException(
+ "Cannot find callback method " + callbackSignature);
+ }
+
+ // Warn if the same callback is used by several subscribers
+ if (callbackSet.contains(callbackSignature)) {
+ warn("The callback method is already used by another subscriber : "
+ + callbackSignature);
+ } else {
+ callbackSet.add(callbackSignature);
+ }
+
+ // Check name is unique
+ if (nameSet.contains(name)) {
+ throw new ConfigurationException(
+ "A subscriber with the same name already exists : "
+ + name);
+ }
+ nameSet.add(name);
+ }
+
+ m_description = new EventAdminSubscriberHandlerDescription(this,
+ subscribers);
+
+ } else {
+ info(LOG_PREFIX + "No subscriber to check");
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param metadata the omponent type metadata
+ * @param conf the instance configuration
+ * @throws ConfigurationException if one event subscription is not correct
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary conf)
+ throws ConfigurationException {
+
+ // Store the component manager
+ m_manager = getInstanceManager();
+
+ // Get the topics and filter instance configuration
+ Dictionary instanceTopics = (Dictionary) conf.get(TOPICS_PROPERTY);
+ Dictionary instanceFilter = (Dictionary) conf.get(FILTER_PROPERTY);
+
+ // Get Metadata subscribers
+ Element[] subscribers = metadata.getElements("subscriber", NAMESPACE);
+
+ // The topics to listen
+ Set topics = new TreeSet();
+
+ if (subscribers != null) {
+
+ // Configure all subscribers
+ for (int i = 0; i < subscribers.length; i++) {
+
+ // Extract the subscriber configuration
+ EventAdminSubscriberMetadata subscriberMetadata = new EventAdminSubscriberMetadata(
+ m_manager.getContext(), subscribers[i]);
+ String name = subscriberMetadata.getName();
+ info(LOG_PREFIX + "Configuring subscriber " + name);
+
+ // Get the topics instance configuration if redefined
+ String topicsString = (instanceTopics != null) ? (String) instanceTopics.get(name) : null;
+ if (topicsString != null) {
+ subscriberMetadata.setTopics(topicsString);
+ }
+
+ // Get the filter instance configuration if redefined
+ String filterString = (instanceFilter != null) ? (String) instanceFilter.get(name) : null;
+ if (filterString != null) {
+ subscriberMetadata.setFilter(filterString);
+ }
+
+ // Check the publisher is correctly configured
+ subscriberMetadata.check();
+
+ // Add this subscriber's topics to the global list
+ String[] subscriberTopics = subscriberMetadata.getTopics();
+ for (int j = 0; j < subscriberTopics.length; j++) {
+ topics.add(subscriberTopics[j]);
+ }
+
+ // Determine the event callback prototype
+ PojoMetadata pojoMetadata = getPojoMetadata();
+ String callbackType;
+ if (subscriberMetadata.getDataKey() == null) {
+ callbackType = Event.class.getName();
+ } else {
+ callbackType = subscriberMetadata.getDataType().getName();
+ }
+
+ // Create the specified callback and register it
+ MethodMetadata methodMetadata = pojoMetadata.getMethod(
+ subscriberMetadata.getCallback(),
+ new String[] { callbackType });
+ Callback callback = new Callback(methodMetadata, m_manager);
+ m_callbacksByName.put(name, callback);
+
+ // Add the subscriber list gloal map
+ m_subscribersByName.put(name, subscriberMetadata);
+ }
+
+ // Construct the global topic list
+ m_topics = new String[topics.size()];
+ int i = 0;
+ for (Iterator iterator = topics.iterator(); iterator.hasNext();) {
+ String tmp = (String) iterator.next();
+ m_topics[i++] = tmp;
+ }
+
+ m_description = new EventAdminSubscriberHandlerDescription(this,
+ subscribers);
+
+ } else {
+ info(LOG_PREFIX + "No subscriber to configure");
+ }
+ }
+
+ /**
+ * Handler start method.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public synchronized void start() {
+ m_isListening = true;
+ }
+
+ /**
+ * Handler stop method.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public synchronized void stop() {
+ m_isListening = false;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /***************************************************************************
+ * OSGi EventHandler callback
+ **************************************************************************/
+
+ /**
+ * Receives an event. The event is dispatch to attached subscribers.
+ *
+ * @param event the received event.
+ * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
+ */
+ public void handleEvent(final Event event) {
+ EventAdminSubscriberMetadata subscriberMetadata = null;
+ // Retrieve the event's topic
+ String topic = event.getTopic();
+
+ // For each subscribers
+ Collection subscribers = m_subscribersByName.values();
+ for (Iterator i = subscribers.iterator(); i.hasNext();) {
+ subscriberMetadata = (EventAdminSubscriberMetadata) i.next();
+
+ // Stack confinement
+ boolean isListening = false;
+
+ Object callbackParam = null;
+ Callback callback = null;
+
+ synchronized (this) {
+ isListening = m_isListening;
+ }
+
+ // Check if the subscriber's topic and filter match
+ Filter filter = subscriberMetadata.getFilter();
+
+ if (EventUtil.matches(topic, subscriberMetadata.getTopics())
+ && (filter == null || event.matches(filter))) {
+
+ String name = subscriberMetadata.getName();
+ callback = (Callback) m_callbacksByName.get(name);
+
+ try {
+ // Depending on the subscriber type...
+ callbackParam = getCallbackParameter(event,
+ subscriberMetadata);
+ } catch (ClassCastException e) {
+ // Ignore the data event if type doesn't match
+ warn(LOG_PREFIX + "Ignoring data event : Bad data type", e);
+ } catch (NoSuchFieldException e) {
+ // Ignore events without data field for data events
+ // subscriber
+ warn(LOG_PREFIX + "Ignoring data event : No data", e);
+ }
+ }
+
+
+ // Run the callback (final check to avoid
+ // NullPointerExceptions)
+ if (isListening && callback != null && callbackParam != null) {
+ try {
+ callback.call(new Object[] { callbackParam });
+ } catch (InvocationTargetException e) {
+ error(LOG_PREFIX
+ + "The callback has thrown an exception",
+ e.getTargetException());
+ } catch (Exception e) {
+ error(LOG_PREFIX
+ + "Unexpected exception when calling callback",
+ e);
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Computes the callback parameter.
+ * @param event the event
+ * @param subscriberMetadata the subscribe metadata
+ * @param dataKey the data key
+ * @return the parameter of the callback
+ * @throws ClassCastException the data class does not match the found value.
+ * @throws NoSuchFieldException the datakey is not present in the event.
+ */
+ private Object getCallbackParameter(final Event event,
+ final EventAdminSubscriberMetadata subscriberMetadata
+ ) throws ClassCastException,NoSuchFieldException {
+ String dataKey = subscriberMetadata.getDataKey();
+ if (dataKey == null) {
+ // Generic event subscriber : pass the event to the
+ // registered callback
+ return event;
+ } else {
+ // Check for a data key in the event
+ boolean dataKeyPresent = false;
+ String[] properties = event.getPropertyNames();
+ for (int j = 0; j < properties.length && !dataKeyPresent; j++) {
+ if (dataKey.equals(properties[j])) {
+ dataKeyPresent = true;
+ }
+ }
+
+ if (dataKeyPresent) {
+ // Data event : check type compatibility and
+ // pass the given object to the registered
+ // callback
+ Object data = event.getProperty(dataKey);
+ Class dataType = subscriberMetadata.getDataType();
+ Class dataClazz = data.getClass();
+ if (dataType.isAssignableFrom(dataClazz)) {
+ return data;
+ } else {
+ throw new ClassCastException("Cannot convert " + dataClazz.getName() + " to "
+ + dataType.getName());
+ }
+ } else {
+ throw new java.lang.NoSuchFieldException(dataKey);
+ }
+
+ }
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandlerDescription.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandlerDescription.java
new file mode 100644
index 0000000..1f9e41f
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandlerDescription.java
@@ -0,0 +1,61 @@
+/*
+ * 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.handlers.event.subscriber;
+
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Event Admin Subscriber Handler Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminSubscriberHandlerDescription extends HandlerDescription {
+
+ /**
+ * List of subscribers.
+ */
+ private Element[] m_subscribersDescriptions;
+
+ /**
+ * Creates a {@link EventAdminSubscriberHandlerDescription}
+ * @param handler the handler
+ * @param subscribers the subscribers
+ */
+ public EventAdminSubscriberHandlerDescription(Handler handler, Element[] subscribers) {
+ super(handler);
+ m_subscribersDescriptions = subscribers;
+ }
+
+ /**
+ * Gets the handler info.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element root = super.getHandlerInfo();
+ if (m_subscribersDescriptions != null) {
+ for (int i = 0; i < m_subscribersDescriptions.length; i++) {
+ Element description = m_subscribersDescriptions[i];
+ root.addElement(description);
+ }
+ }
+ return root;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java
new file mode 100644
index 0000000..3d9f0a5
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java
@@ -0,0 +1,305 @@
+/*
+ * 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.handlers.event.subscriber;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.handlers.event.EventUtil;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Represent an subscriber.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+class EventAdminSubscriberMetadata {
+
+ // Names of metadata attributes
+
+ /**
+ * The name attribute in the component metadata.
+ */
+ public static final String NAME_ATTRIBUTE = "name";
+
+ /**
+ * The callback attribute in the component metadata.
+ */
+ public static final String CALLBACK_ATTRIBUTE = "callback";
+
+ /**
+ * The topics attribute in the component metadata.
+ */
+ public static final String TOPICS_ATTRIBUTE = "topics";
+
+ /**
+ * The data key attribute in the component metadata.
+ */
+ public static final String DATA_KEY_ATTRIBUTE = "data-key";
+
+ /**
+ * The data type attribute in the component metadata.
+ */
+ public static final String DATA_TYPE_ATTRIBUTE = "data-type";
+
+ /**
+ * The filter attribute in the component metadata.
+ */
+ public static final String FILTER_ATTRIBUTE = "filter";
+
+ // Default values
+
+ /**
+ * The data type atttribute's default value.
+ */
+ public static final Class DEFAULT_DATA_TYPE_VALUE = java.lang.Object.class;
+
+ /**
+ * The name which acts as an identifier.
+ */
+ private final String m_name;
+
+ /**
+ * Name of the callback method.
+ */
+ private final String m_callback;
+
+ /**
+ * Listened topics.
+ */
+ private String[] m_topics;
+
+ /**
+ * The key where user data are stored in the event dictionary.
+ */
+ private String m_dataKey;
+
+ /**
+ * The type of received data.
+ */
+ private final Class m_dataType;
+
+ /**
+ * Event filter.
+ */
+ private Filter m_filter;
+
+ /**
+ * The context of the bundle.
+ */
+ private final BundleContext m_bundleContext;
+
+ /**
+ * Constructor.
+ *
+ * @param bundleContext the bundle context of the managed instance.
+ * @param subscriber the subscriber metadata.
+ * @throws ConfigurationException if the configuration of the component or
+ * the instance is invalid.
+ */
+ public EventAdminSubscriberMetadata(BundleContext bundleContext,
+ Element subscriber) throws ConfigurationException {
+ m_bundleContext = bundleContext;
+
+ /**
+ * Setup required attributes
+ */
+
+ // NAME_ATTRIBUTE
+ if (subscriber.containsAttribute(NAME_ATTRIBUTE)) {
+ m_name = subscriber.getAttribute(NAME_ATTRIBUTE);
+ } else {
+ throw new ConfigurationException(
+ "Missing required attribute in component configuration : "
+ + NAME_ATTRIBUTE);
+ }
+
+ // CALLBACK_ATTRIBUTE
+ if (subscriber.containsAttribute(CALLBACK_ATTRIBUTE)) {
+ m_callback = subscriber.getAttribute(CALLBACK_ATTRIBUTE);
+ } else if (subscriber.containsAttribute("method")) {
+ m_callback = subscriber.getAttribute("method");
+ } else {
+ throw new ConfigurationException(
+ "Missing required attribute in component configuration : "
+ + CALLBACK_ATTRIBUTE);
+ }
+
+ // TOPICS_ATTRIBUTE
+ if (subscriber.containsAttribute(TOPICS_ATTRIBUTE)) {
+ setTopics(subscriber.getAttribute(TOPICS_ATTRIBUTE));
+ } else {
+ m_topics = null;
+ // Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+ // overridden in the instance configuration.
+ }
+
+ /**
+ * Setup optional attributes
+ */
+
+ // DATA_KEY_ATTRIBUTE
+ m_dataKey = subscriber.getAttribute(DATA_KEY_ATTRIBUTE);
+ if (m_dataKey == null) { // Alternative configurations (data_key and dataKey)
+ // XML
+ m_dataKey = subscriber.getAttribute("data_key");
+ if (m_dataKey == null) {
+ // Annotation
+ m_dataKey = subscriber.getAttribute("dataKey");
+ }
+ }
+
+ String t = subscriber.getAttribute(DATA_TYPE_ATTRIBUTE);
+ if (t == null) { // Alternative configurations
+ // XML
+ t = subscriber.getAttribute("data_type");
+ if (t == null) {
+ /// Annotation
+ t = subscriber.getAttribute("dataType");
+ }
+ }
+
+ if (t != null) {
+ // Check that the data-key attribute is set.
+ if (m_dataKey == null) {
+ throw new ConfigurationException(
+ "Missing attribute in component configuration : "
+ + DATA_KEY_ATTRIBUTE);
+ }
+ Class type;
+ try {
+ type = m_bundleContext.getBundle().loadClass(t);
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Data type class not found : "
+ + t);
+ }
+ m_dataType = type;
+ } else {
+ m_dataType = DEFAULT_DATA_TYPE_VALUE;
+ }
+
+ // FILTER_ATTRIBUTE
+ if (subscriber.containsAttribute(FILTER_ATTRIBUTE)) {
+ setFilter(subscriber.getAttribute(FILTER_ATTRIBUTE));
+ }
+ }
+
+ /**
+ * Sets the topics attribute of the subscriber.
+ *
+ * @param topicsString the comma separated list of the topics to listen
+ * @throws ConfigurationException if the specified topic list is malformed
+ */
+ public void setTopics(String topicsString) throws ConfigurationException {
+ String[] newTopics = ParseUtils.split(topicsString,
+ EventUtil.TOPIC_SEPARATOR);
+ // Check each topic is valid
+ for (int i = 0; i < newTopics.length; i++) {
+ String topicScope = newTopics[i];
+ if (!EventUtil.isValidTopicScope(topicScope)) {
+ throw new ConfigurationException("Invalid topic scope : \""
+ + topicScope + "\".");
+ }
+ }
+ m_topics = newTopics;
+ }
+
+ /**
+ * Sets the filter attribute of the subscriber.
+ *
+ * @param filterString the string representation of the event filter
+ * @throws ConfigurationException if the LDAP filter is malformed
+ */
+ public void setFilter(String filterString) throws ConfigurationException {
+ try {
+ m_filter = m_bundleContext.createFilter(filterString);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("Invalid filter syntax");
+ }
+ }
+
+ /**
+ * Checks that the required instance configurable attributes are all set.
+ *
+ * @throws ConfigurationException if a required attribute is missing
+ */
+ public void check() throws ConfigurationException {
+ if (m_topics == null || m_topics.length == 0) {
+ throw new ConfigurationException(
+ "Missing required attribute in component or instance configuration : "
+ + TOPICS_ATTRIBUTE);
+ }
+ }
+
+ /**
+ * Gets the name attribute of the subscriber.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets the topics attribute of the subscriber.
+ *
+ * @return the topics
+ */
+ public String[] getTopics() {
+ return m_topics;
+ }
+
+ /**
+ * Gets the callback attribute of the subscriber.
+ *
+ * @return the callback
+ */
+ public String getCallback() {
+ return m_callback;
+ }
+
+ /**
+ * Gets the data key attribute of the subscriber.
+ *
+ * @return the dataKey
+ */
+ public String getDataKey() {
+ return m_dataKey;
+ }
+
+ /**
+ * Gets the data type attribute of the subscriber.
+ *
+ * @return the dataType
+ */
+ public Class getDataType() {
+ return m_dataType;
+ }
+
+ /**
+ * Gets the filter attribute of the subscriber.
+ *
+ * @return the filter
+ */
+ public Filter getFilter() {
+ return m_filter;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler/src/main/resources/event-admin.xsd b/ipojo/handler/eventadmin/eventadmin-handler/src/main/resources/event-admin.xsd
new file mode 100644
index 0000000..b9c8271
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler/src/main/resources/event-admin.xsd
@@ -0,0 +1,90 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.event"
+ xmlns="org.apache.felix.ipojo.handlers.event"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+
+ <xs:complexType name="PublisherType">
+ <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: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>
+ <xs:element name="subscriber" type="SubscriberType"></xs:element>
+
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/pom.xml b/ipojo/handler/eventadmin/pom.xml
new file mode 100644
index 0000000..c8f5604
--- /dev/null
+++ b/ipojo/handler/eventadmin/pom.xml
@@ -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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.event-admin-handler-project</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Event Admin Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>eventadmin-handler</module>
+ <module>eventadmin-handler-it</module>
+ </modules>
+
+</project>
diff --git a/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/eventadmin/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/extender/changelog.txt b/ipojo/handler/extender/changelog.txt
new file mode 100644
index 0000000..6c7810a
--- /dev/null
+++ b/ipojo/handler/extender/changelog.txt
@@ -0,0 +1,26 @@
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1025] - iPOJO Extender Handler hold a lock during its initialization
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Bug
+ * [FELIX-613] - Extender pattern handler issue when bundles are leaving
+
+** Improvement
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/extender/metadata.xml b/ipojo/handler/extender/metadata.xml
new file mode 100644
index 0000000..68c4aa0
--- /dev/null
+++ b/ipojo/handler/extender/metadata.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <handler
+ classname="org.apache.felix.ipojo.handler.extender.ExtenderModelHandler"
+ name="extender" namespace="org.apache.felix.ipojo.extender">
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/extender/obr.xml b/ipojo/handler/extender/obr.xml
new file mode 100644
index 0000000..34b8e0e
--- /dev/null
+++ b/ipojo/handler/extender/obr.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="extender"/>
+ <p n="namespace" v="org.apache.felix.ipojo.extender"/>
+ <p n="type" v="primitive"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/handler/extender/pom.xml b/ipojo/handler/extender/pom.xml
new file mode 100644
index 0000000..cb8dc5e
--- /dev/null
+++ b/ipojo/handler/extender/pom.xml
@@ -0,0 +1,102 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Extender Pattern Handler</name>
+ <artifactId>org.apache.felix.ipojo.handler.extender</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+
+ <description>
+ iPOJO extension to implement an extender pattern (host).
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/extender-pattern-handler.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Extender Pattern Handler
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/extender-pattern-handler.html
+ </Bundle-DocURL>
+ <Private-Package>org.apache.felix.ipojo.handler.extender
+ </Private-Package>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <metadata>metadata.xml</metadata>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/handler/extender/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/extender/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/extender/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/extender/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/extender/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/extender/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java
new file mode 100644
index 0000000..2f39ccc
--- /dev/null
+++ b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/BundleTracker.java
@@ -0,0 +1,157 @@
+/*
+ * 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.handler.extender;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ * This is a very simple bundle tracker utility class that tracks active
+ * bundles. The tracker must be given a bundle context upon creation,
+ * which it uses to listen for bundle events. The bundle tracker must be
+ * opened to track objects and closed when it is no longer needed. This
+ * class is abstract, which means in order to use it you must create a
+ * subclass of it. Subclasses must implement the <tt>addedBundle()</tt>
+ * and <tt>removedBundle()</tt> methods, which can be used to perform some
+ * custom action upon the activation or deactivation of bundles. Since this
+ * tracker is quite simple, its concurrency control approach is also
+ * simplistic. This means that subclasses should take great care to ensure
+ * that their <tt>addedBundle()</tt> and <tt>removedBundle()</tt> methods
+ * are very simple and do not do anything to change the state of any bundles.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ **/
+public abstract class BundleTracker {
+ /**
+ * Set of tracked bundles.
+ */
+ final Set m_bundleSet = new HashSet();
+
+ /**
+ * Bundle context.
+ */
+ final BundleContext m_context;
+
+ /**
+ * Synchronous bundle listener.
+ */
+ final SynchronousBundleListener m_listener;
+
+ /**
+ * Flag indicating if the tracking is open.
+ */
+ boolean m_open;
+
+ /**
+ * Constructs a bundle tracker object that will use the specified
+ * bundle context.
+ * @param context the bundle context to use to track bundles.
+ **/
+ public BundleTracker(BundleContext context) {
+ m_context = context;
+ m_listener = new SynchronousBundleListener() {
+ public void bundleChanged(BundleEvent evt) {
+ synchronized (BundleTracker.this) {
+ if (!m_open) { return; }
+
+ if (evt.getType() == BundleEvent.STARTED) {
+ if (!m_bundleSet.contains(evt.getBundle())) {
+ m_bundleSet.add(evt.getBundle());
+ addedBundle(evt.getBundle());
+ }
+ } else if (evt.getType() == BundleEvent.STOPPED) {
+ if (m_bundleSet.contains(evt.getBundle())) {
+ m_bundleSet.remove(evt.getBundle());
+ removedBundle(evt.getBundle());
+ }
+ }
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns the current set of active bundles.
+ * @return the current set of active bundles.
+ **/
+ public synchronized Bundle[] getBundles() {
+ return (Bundle[]) m_bundleSet.toArray(new Bundle[m_bundleSet.size()]);
+ }
+
+ /**
+ * Call this method to start the tracking of active bundles.
+ **/
+ public void open() {
+ synchronized (this) {
+ if (!m_open) {
+ m_open = true;
+
+ m_context.addBundleListener(m_listener);
+ }
+ }
+
+ Bundle[] bundles = m_context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if (bundles[i].getState() == Bundle.ACTIVE) {
+ if (m_bundleSet.add(bundles[i])) {
+ addedBundle(bundles[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Call this method to stop the tracking of active bundles.
+ **/
+ public synchronized void close() {
+ if (m_open) {
+ m_open = false;
+
+ m_context.removeBundleListener(m_listener);
+
+ Bundle[] bundles = (Bundle[]) m_bundleSet.toArray(new Bundle[m_bundleSet.size()]);
+ for (int i = 0; i < bundles.length; i++) {
+ if (m_bundleSet.remove(bundles[i])) {
+ removedBundle(bundles[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Subclasses must implement this method; it can be used to perform
+ * actions upon the activation of a bundle. Subclasses should keep
+ * this method implementation as simple as possible and should not
+ * cause the change in any bundle state to avoid concurrency issues.
+ * @param bundle the bundle being added to the active set.
+ **/
+ protected abstract void addedBundle(Bundle bundle);
+
+ /**
+ * Subclasses must implement this method; it can be used to perform
+ * actions upon the deactivation of a bundle. Subclasses should keep
+ * this method implementation as simple as possible and should not
+ * cause the change in any bundle state to avoid concurrency issues.
+ * @param bundle the bundle being removed from the active set.
+ **/
+ protected abstract void removedBundle(Bundle bundle);
+}
diff --git a/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java
new file mode 100644
index 0000000..5d01869
--- /dev/null
+++ b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderManager.java
@@ -0,0 +1,135 @@
+/*
+ * 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.handler.extender;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.util.Callback;
+import org.osgi.framework.Bundle;
+
+/**
+ * Track and manage extensions.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ExtenderManager extends BundleTracker {
+
+ /**
+ * Looked extension.
+ */
+ private String m_extension;
+
+ /**
+ * OnArrival method.
+ */
+ private Callback m_onArrival;
+
+ /**
+ * OnDeparture method.
+ */
+ private Callback m_onDeparture;
+
+ /**
+ * Attached handler.
+ */
+ private PrimitiveHandler m_handler;
+
+ /**
+ * Set of managed bundles.
+ */
+ private Set m_bundles = new HashSet();
+
+ /**
+ * Constructor.
+ * @param handler the attached handler.
+ * @param extension the looked extension.
+ * @param bind the onArrival method
+ * @param unbind the onDeparture method.
+ */
+ public ExtenderManager(ExtenderModelHandler handler, String extension, String bind, String unbind) {
+ super(handler.getInstanceManager().getContext());
+ m_handler = handler;
+ m_onArrival = new Callback(bind, new Class[] {Bundle.class, String.class}, false, m_handler.getInstanceManager());
+ m_onDeparture = new Callback(unbind, new Class[] {Bundle.class}, false, m_handler.getInstanceManager());
+ m_extension = extension;
+ }
+
+
+ /**
+ * A bundle arrives.
+ * Checks if the bundle match with the looked extension, if so call the arrival callback.
+ * @param bundle the arriving bundle.
+ * @see org.apache.felix.ipojo.handler.extender.BundleTracker#addedBundle(org.osgi.framework.Bundle)
+ */
+ protected void addedBundle(Bundle bundle) {
+ Dictionary headers = bundle.getHeaders();
+ String header = (String) headers.get(m_extension);
+ if (header != null) {
+ synchronized (this) {
+ m_bundles.add(bundle);
+ }
+ try { // Call the callback outside the synchronized block.
+ m_onArrival.call(new Object[] {bundle, header});
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " does not exist in the class", e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " cannot be called", e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " has thrown an exception", e.getTargetException());
+ m_handler.getInstanceManager().stop();
+ }
+ }
+ }
+
+ /**
+ * A bundle is stopping.
+ * Check if the bundle was managed, if so call the remove departure callback.
+ * @param bundle the leaving bundle.
+ * @see org.apache.felix.ipojo.handler.extender.BundleTracker#removedBundle(org.osgi.framework.Bundle)
+ */
+ protected void removedBundle(Bundle bundle) {
+ boolean contained;
+ synchronized (this) {
+ contained = m_bundles.remove(bundle); // Stack confinement
+ }
+
+ if (contained) {
+ try {
+ m_onDeparture.call(new Object[] {bundle});
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " does not exist in the class", e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " cannot be called", e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " has thrown an exception", e.getTargetException());
+ m_handler.getInstanceManager().stop();
+ }
+ }
+ }
+
+
+
+}
diff --git a/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.java
new file mode 100644
index 0000000..ec4356d
--- /dev/null
+++ b/ipojo/handler/extender/src/main/java/org/apache/felix/ipojo/handler/extender/ExtenderModelHandler.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.handler.extender;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Handler automating extender pattern. The component using this handler is notified
+ * when an handler with a special manifest extension is detected, the component is notified.
+ * When a managed handler leaves, the component is also notified.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ExtenderModelHandler extends PrimitiveHandler {
+
+ /**
+ * The handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.extender";
+
+ /**
+ * The extension manager list.
+ * Immutable once set.
+ */
+ private List m_managers = new ArrayList(1);
+
+ /**
+ * Configures the handler.
+ * @param elem the component type element.
+ * @param dict the instance configuration.
+ * @throws ConfigurationException if the configuration is not valid.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element elem, Dictionary dict) throws ConfigurationException {
+ Element[] elems = elem.getElements("extender", NAMESPACE);
+ for (int i = 0; i < elems.length; i++) {
+ String extension = elems[i].getAttribute("extension");
+ String onArrival = elems[i].getAttribute("onArrival");
+ String onDeparture = elems[i].getAttribute("onDeparture");
+
+ if (extension == null) {
+ throw new ConfigurationException("The extender element requires an 'extender' attribute");
+ }
+ if (onArrival == null || onDeparture == null) {
+ throw new ConfigurationException("The extender element requires the 'onArrival' and 'onDeparture' attributes");
+ }
+
+ ExtenderManager wbm = new ExtenderManager(this, extension, onArrival, onDeparture);
+ m_managers.add(wbm);
+ }
+
+ }
+
+ /**
+ * Starts the handler.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ for (int i = 0; i < m_managers.size(); i++) {
+ ((ExtenderManager) m_managers.get(i)).open();
+ }
+ }
+
+ /**
+ * Stops the handler.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_managers.size(); i++) {
+ ((ExtenderManager) m_managers.get(i)).close();
+ }
+ }
+
+}
diff --git a/ipojo/handler/extender/src/main/resources/extender-pattern.xsd b/ipojo/handler/extender/src/main/resources/extender-pattern.xsd
new file mode 100644
index 0000000..0e2ed9f
--- /dev/null
+++ b/ipojo/handler/extender/src/main/resources/extender-pattern.xsd
@@ -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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.extender"
+ xmlns="org.apache.felix.ipojo.extender"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="extender" type="ExtenderType"></xs:element>
+ <xs:complexType name="ExtenderType">
+ <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
diff --git a/ipojo/handler/jmx/changelog.txt b/ipojo/handler/jmx/changelog.txt
new file mode 100644
index 0000000..87556fc
--- /dev/null
+++ b/ipojo/handler/jmx/changelog.txt
@@ -0,0 +1,23 @@
+Changes from 1.4.0 to 1.6.0
+---------------------------
+** Improvement
+ * [FELIX-2633] - Rename JMX annotations
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1183] - iPOJO JMX handler doesn't re-throw exceptions
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-828] - iPOJO JMX Handler: the name attribute has not the expected behavior
+ * [FELIX-829] - iPOJO JMX Handler: the sub-element should refer to the handler namespace
+
+Version 1.0.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/jmx/jmx-handler-it/pom.xml b/ipojo/handler/jmx/jmx-handler-it/pom.xml
new file mode 100644
index 0000000..d39c41b
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/pom.xml
@@ -0,0 +1,389 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
+ <name>Apache Felix iPOJO JMX Handler - Integration Test</name>
+ <artifactId>org.apache.felix.ipojo.handler.jmx-it</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.1</url.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.jmx</artifactId>
+ <version>${project.version}</version>
+ <!--
+ The event admin handler depends on an older version of the compendium and core, to avoid issue during
+ tests, we must exclude those artifacts and trust the framework to provide the right / compatible
+ version
+ -->
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.6</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>regular</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/regular</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>test-all</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>equinox-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>equinox</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/equinox-native</cloneProjectsTo>
+
+ </configuration>
+ </execution>
+ <execution>
+ <id>felix-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/felix-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knopflerfish-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>knopflerfish</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/knopflerfish-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+</project>
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/pom.xml b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/pom.xml
new file mode 100644
index 0000000..d07cbcf
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.jmx-it</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-jmx-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponent.java b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponent.java
new file mode 100644
index 0000000..a99e097
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponent.java
@@ -0,0 +1,55 @@
+/*
+ * 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.handler.jmx.components;
+
+/**
+ * Simple component that holds an integer. It is exposed as a MBean.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SimpleManagedComponent {
+
+ /**
+ * The integer.
+ */
+ private int m_integer /*= new Random().nextInt()*/;
+
+ /**
+ * Set the value of the integer.
+ * @param newValue the new value
+ * @return the old value of the integer.
+ */
+ @SuppressWarnings("unused")
+ private synchronized int setIntegerValue(int newValue) {
+ int oldValue = m_integer;
+ m_integer = newValue;
+ return oldValue;
+ }
+
+ /**
+ * Get the value of the integer.
+ * @return the currentvalue of the integer.
+ */
+ @SuppressWarnings("unused")
+ private synchronized int getIntegerValue() {
+ return m_integer;
+ }
+
+}
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotated.java b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotated.java
new file mode 100644
index 0000000..96a5f4f
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotated.java
@@ -0,0 +1,69 @@
+/*
+ * 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.handler.jmx.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.jmx.JMXBean;
+import org.apache.felix.ipojo.handlers.jmx.JMXMethod;
+import org.apache.felix.ipojo.handlers.jmx.JMXProperty;
+
+import java.util.Random;
+
+/**
+ * Simple component that holds an integer. It is exposed as a MBean. This
+ * version uses the brand new annotations of the JMX handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component(immediate = true)
+@JMXBean
+public class SimpleManagedComponentAnnotated {
+
+ /**
+ * The integer.
+ */
+ @JMXProperty(name = "integer", rights = "r", notification = true)
+ private int m_integer = new Random().nextInt();;
+
+ /**
+ * Set the value of the integer.
+ *
+ * @param newValue
+ * the new value
+ * @return the old value of the integer.
+ */
+ @SuppressWarnings("unused")
+ @JMXMethod(description = "Set the value of the integer")
+ private synchronized int setIntegerValue(int newValue) {
+ int oldValue = m_integer;
+ m_integer = newValue;
+ return oldValue;
+ }
+
+ /**
+ * Get the value of the integer.
+ *
+ * @return the currentvalue of the integer.
+ */
+ @SuppressWarnings("unused")
+ @JMXMethod(description = "Get the value of the integer")
+ private synchronized int getIntegerValue() {
+ return m_integer;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotatedDeprecated.java b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotatedDeprecated.java
new file mode 100644
index 0000000..5720b67
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/java/org/apache/felix/ipojo/handler/jmx/components/SimpleManagedComponentAnnotatedDeprecated.java
@@ -0,0 +1,70 @@
+/*
+ * 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.handler.jmx.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.jmx.Config;
+import org.apache.felix.ipojo.handlers.jmx.Method;
+import org.apache.felix.ipojo.handlers.jmx.Property;
+
+import java.util.Random;
+
+
+/**
+ * Simple component that holds an integer. It is exposed as a MBean. This
+ * version uses the deprecated annotations of the JMX handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component(immediate = true)
+@Config
+public class SimpleManagedComponentAnnotatedDeprecated {
+
+ /**
+ * The integer.
+ */
+ @Property(name = "integer", rights = "r", notification = true)
+ private int m_integer = new Random().nextInt();;
+
+ /**
+ * Set the value of the integer.
+ *
+ * @param newValue
+ * the new value
+ * @return the old value of the integer.
+ */
+ @SuppressWarnings("unused")
+ @Method(description = "Set the value of the integer")
+ private synchronized int setIntegerValue(int newValue) {
+ int oldValue = m_integer;
+ m_integer = newValue;
+ return oldValue;
+ }
+
+ /**
+ * Get the value of the integer.
+ *
+ * @return the currentvalue of the integer.
+ */
+ @SuppressWarnings("unused")
+ @Method(description = "Get the value of the integer")
+ private synchronized int getIntegerValue() {
+ return m_integer;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/resources/metadata.xml b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/resources/metadata.xml
new file mode 100644
index 0000000..ac908ab
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/main/resources/metadata.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:jmx="org.apache.felix.ipojo.handlers.jmx">
+
+ <!-- The simple managed component without annotations and with brand new JMX handler syntax -->
+ <component classname="org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponent" immediate="true">
+ <!-- Expose field and methods with JMX handler -->
+ <jmx:config>
+ <jmx:jmxmethod name="getIntegerValue" description="Get the value of the integer"/>
+ <jmx:jmxmethod name="setIntegerValue" description="Set the value of the integer"/>
+ <jmx:jmxproperty name="integer" field="m_integer" rights="r" notification="true"/>
+ </jmx:config>
+ </component>
+
+ <!-- The simple managed component without annotations and with brand new JMX handler syntax -->
+ <component classname="org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponent" immediate="true" name="org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentDeprecated">
+ <!-- Expose field and methods with JMX handler -->
+ <jmx:config>
+ <jmx:method name="getIntegerValue" description="Get the value of the integer"/>
+ <jmx:method name="setIntegerValue" description="Set the value of the integer"/>
+ <jmx:property name="integer" field="m_integer" rights="r" notification="true"/>
+ </jmx:config>
+ </component>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/Common.java b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/Common.java
new file mode 100644
index 0000000..971fe0c
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/Common.java
@@ -0,0 +1,216 @@
+/*
+ * 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.handler.jmx.test;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * Bootstrap the test from this project
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class Common {
+
+ @Inject
+ BundleContext bc;
+
+ OSGiHelper osgiHelper;
+ IPOJOHelper ipojoHelper;
+
+ Bundle testedBundle;
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(Level.DEBUG);
+
+ return options(
+ cleanCaches(),
+ ipojoBundles(),
+ junitBundles(),
+ testedBundle(),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN")
+ );
+ }
+
+ public static Option junitAndMockitoBundles() {
+ return new DefaultCompositeOption(
+ // Repository required to load harmcrest (OSGi-fied version).
+ repository("http://repository.springsource.com/maven/bundles/external").id(
+ "com.springsource.repository.bundles.external"),
+
+ // Hamcrest with a version matching the range expected by Mockito
+ mavenBundle("org.hamcrest", "com.springsource.org.hamcrest.core", "1.1.0"),
+
+ // Mockito core does not includes Hamcrest
+ mavenBundle("org.mockito", "mockito-core", "1.9.5"),
+
+ // Objenesis with a version matching the range expected by Mockito
+ wrappedBundle(mavenBundle("org.objenesis", "objenesis", "1.2"))
+ .exports("*;version=1.2"),
+
+ // The default JUnit bundle also exports Hamcrest, but with an (incorrect) version of
+ // 4.9 which does not match the Mockito import. When deployed after the hamcrest bundles, it gets
+ // resolved correctly.
+ CoreOptions.junitBundles(),
+
+ /*
+ * Felix has implicit boot delegation enabled by default. It conflicts with Mockito:
+ * java.lang.LinkageError: loader constraint violation in interface itable initialization:
+ * when resolving method "org.osgi.service.useradmin.User$$EnhancerByMockitoWithCGLIB$$dd2f81dc
+ * .newInstance(Lorg/mockito/cglib/proxy/Callback;)Ljava/lang/Object;" the class loader
+ * (instance of org/mockito/internal/creation/jmock/SearchingClassLoader) of the current class,
+ * org/osgi/service/useradmin/User$$EnhancerByMockitoWithCGLIB$$dd2f81dc, and the class loader
+ * (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) for interface
+ * org/mockito/cglib/proxy/Factory have different Class objects for the type org/mockito/cglib/
+ * proxy/Callback used in the signature
+ *
+ * So we disable the bootdelegation. this property has no effect on the other OSGi implementation.
+ */
+ frameworkProperty("felix.bootdelegation.implicit").value("false")
+ );
+ }
+
+ @Before
+ public void commonSetUp() {
+ osgiHelper = new OSGiHelper(bc);
+ ipojoHelper = new IPOJOHelper(bc);
+
+ testedBundle = osgiHelper.getBundle("test.bundle");
+
+ // Dump OSGi Framework information
+ String vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VENDOR);
+ if (vendor == null) {
+ vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_SYMBOLICNAME);
+ }
+ String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
+ System.out.println("OSGi Framework : " + vendor + " - " + version);
+ }
+
+ @After
+ public void commonTearDown() {
+ ipojoHelper.dispose();
+ osgiHelper.dispose();
+ }
+
+ public static CompositeOption ipojoBundles() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo").versionAsInProject(),
+ mavenBundle("org.ow2.chameleon.testing", "osgi-helpers").versionAsInProject(),
+ // The tested handler
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.jmx").versionAsInProject()
+ );
+ }
+
+ public Option testedBundle() throws MalformedURLException {
+ File out = new File("target/tested/bundle.jar");
+
+ TinyBundle tested = TinyBundles.bundle();
+
+ // We look inside target/classes to find the class and resources
+ File classes = new File("target/classes");
+ Collection<File> files = FileUtils.listFilesAndDirs(classes, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
+ List<File> services = new ArrayList<File>();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // By convention we export of .services and .service package
+ if (file.getName().endsWith("services") || file.getName().endsWith("service")) {
+ services.add(file);
+ }
+ } else {
+ // We need to compute the path
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ tested.add(path, file.toURI().toURL());
+ System.out.println(file.getName() + " added to " + path);
+ }
+ }
+
+ String export = "";
+ for (File file : services) {
+ if (export.length() > 0) { export += ", "; }
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ String packageName = path.replace('/', '.');
+ export += packageName;
+ }
+
+ System.out.println("Exported packages : " + export);
+
+ InputStream inputStream = tested
+ .set(Constants.BUNDLE_SYMBOLICNAME, "test.bundle")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ //.set(Constants.EXPORT_PACKAGE, export) // No export...
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources")));
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the manipulated bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the manipulated bundle");
+ }
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+
+
+}
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/TestMBean.java b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/TestMBean.java
new file mode 100644
index 0000000..0e52bf6
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/it/jmx-it/src/test/java/org/apache/felix/ipojo/handler/jmx/test/TestMBean.java
@@ -0,0 +1,224 @@
+/*
+ * 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.handler.jmx.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+
+import javax.management.*;
+import java.lang.management.ManagementFactory;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestMBean extends Common {
+
+ /**
+ * The MBean server used to access exposed MBeans.
+ */
+ private MBeanServer m_server;
+
+ /**
+ * Initialize test.
+ */
+ @Before
+ public void setUp() {
+ m_server = ManagementFactory.getPlatformMBeanServer();
+ for (Bundle bundle : bc.getBundles()) {
+ System.out.println(bundle.getSymbolicName() + " - " + bundle.getState());
+ }
+ }
+
+ /**
+ * Test the MBean exposed by the simple component, defined without
+ * annotations and with the brand new JMX handler syntax.
+ */
+ @Test
+ public void testMBeanWithoutAnnotations() throws MalformedObjectNameException, IntrospectionException, InstanceNotFoundException, ListenerNotFoundException, ReflectionException, MBeanException {
+ // Create an instance of the component
+ ComponentInstance componentInstance = ipojoHelper
+ .createComponentInstance("org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponent");
+ String instanceName = componentInstance.getInstanceName();
+ ObjectName objectName = new ObjectName(
+ "org.apache.felix.ipojo.handler.jmx.components:type=org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponent,instance="
+ + instanceName);
+ doTest(objectName);
+ }
+
+ /**
+ * Test the MBean exposed by the simple component, defined without
+ * annotations and with the deprecated JMX handler syntax.
+ */
+ @Test
+ public void testMBeanWithoutAnnotationsDeprecated() throws MalformedObjectNameException, IntrospectionException, InstanceNotFoundException, ListenerNotFoundException, ReflectionException, MBeanException {
+ // Create an instance of the component
+ ComponentInstance componentInstance = ipojoHelper
+ .createComponentInstance("org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentDeprecated");
+ String instanceName = componentInstance.getInstanceName();
+ ObjectName objectName = new ObjectName(
+ "org.apache.felix.ipojo.handler.jmx.components:type=org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponent,instance="
+ + instanceName);
+ doTest(objectName);
+ }
+
+ /**
+ * Test the MBean exposed by the simple component, defined with
+ * annotations.
+ */
+ @Test
+ public void testMBeanWithAnnotations() throws MalformedObjectNameException, IntrospectionException,
+ InstanceNotFoundException, ListenerNotFoundException,
+ ReflectionException, MBeanException {
+ // Create an instance of the component
+ ComponentInstance componentInstance = ipojoHelper
+ .createComponentInstance("org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentAnnotated");
+ String instanceName = componentInstance.getInstanceName();
+ ObjectName objectName = new ObjectName(
+ "org.apache.felix.ipojo.handler.jmx.components:type=org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentAnnotated,instance="
+ + instanceName);
+ doTest(objectName);
+ }
+
+ /**
+ * Test the MBean exposed by the simple component, defined with
+ * annotations.
+ */
+ @Test
+ public void testMBeanWithAnnotationsDeprecated() throws MalformedObjectNameException, IntrospectionException,
+ InstanceNotFoundException, ListenerNotFoundException,
+ ReflectionException, MBeanException {
+ // Create an instance of the component
+ ComponentInstance componentInstance = ipojoHelper
+ .createComponentInstance("org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentAnnotatedDeprecated");
+ String instanceName = componentInstance.getInstanceName();
+ ObjectName objectName = new ObjectName(
+ "org.apache.felix.ipojo.handler.jmx.components:type=org.apache.felix.ipojo.handler.jmx.components.SimpleManagedComponentAnnotatedDeprecated,instance="
+ + instanceName);
+ doTest(objectName);
+ }
+
+ /**
+ * Utility method used to test the MBean with the given objectName.
+ *
+ * @param objectName the objectName of the MBean to test.
+ */
+ private void doTest(ObjectName objectName) throws IntrospectionException, InstanceNotFoundException, ReflectionException, MBeanException, ListenerNotFoundException {
+
+ // Get the MBean from the platform MBean server
+
+ MBeanInfo mBeanInfo = m_server.getMBeanInfo(objectName);
+ ObjectInstance objectInstance = m_server.getObjectInstance(objectName);
+ assertNotNull(mBeanInfo);
+ assertNotNull(objectInstance);
+ // Check that the property is exposed
+ MBeanAttributeInfo[] attributes = mBeanInfo.getAttributes();
+ assertEquals(1, attributes.length);
+ MBeanAttributeInfo attribute = attributes[0];
+ assertEquals("integer", attribute.getName());
+ assertEquals("int", attribute.getType());
+ assertTrue(attribute.isReadable());
+ assertFalse(attribute.isWritable());
+ // Check that both methods are exposed
+ MBeanOperationInfo[] operations = mBeanInfo.getOperations();
+ assertEquals(2, operations.length);
+ MBeanOperationInfo getOperation;
+ MBeanOperationInfo setOperation;
+ // Order is not important
+ if (operations[0].getName().equals("getIntegerValue")) {
+ getOperation = operations[0];
+ setOperation = operations[1];
+ } else {
+ setOperation = operations[0];
+ getOperation = operations[1];
+ }
+ // Check the 'get' operation
+ assertEquals("getIntegerValue", getOperation.getName());
+ assertEquals("Get the value of the integer",
+ getOperation.getDescription());
+ assertEquals("int", getOperation.getReturnType());
+ MBeanParameterInfo[] getOperationParams = getOperation.getSignature();
+ assertEquals(0, getOperationParams.length);
+ // Check the 'set' operation
+ assertEquals("setIntegerValue", setOperation.getName());
+ assertEquals("Set the value of the integer",
+ setOperation.getDescription());
+ assertEquals("int", setOperation.getReturnType());
+ MBeanParameterInfo[] setOperationParams = setOperation.getSignature();
+ assertEquals(1, setOperationParams.length);
+ assertEquals("int", setOperationParams[0].getType());
+ // Call the methods and test the result, also test notifications
+ CustomNotificationListener listener = new CustomNotificationListener();
+ m_server.addNotificationListener(objectName, listener, null, null);
+ int value1 = 123;
+ int value2 = 456;
+ m_server.invoke(objectName, "setIntegerValue", new Object[]{value1},
+ new String[]{"int"});
+ m_server.invoke(objectName, "setIntegerValue", new Object[]{value2},
+ new String[]{"int"});
+ int result = (Integer) m_server.invoke(objectName, "getIntegerValue",
+ new Object[0], new String[0]);
+ assertEquals(value2, result);
+ m_server.removeNotificationListener(objectName, listener, null, null);
+ //assertEquals(2, listener.getCount());
+ }
+
+ /**
+ * Custom listener used to count MBean notifications.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ private class CustomNotificationListener implements NotificationListener {
+
+ /**
+ * Counter for the notifications.
+ */
+ private int m_counter = 0;
+
+ /**
+ * Notified !
+ *
+ * @param notification the notification
+ * @param handback ignored
+ */
+ public void handleNotification(Notification notification,
+ Object handback) {
+ m_counter++;
+ }
+
+ /**
+ * Return the notification count of this listener.
+ *
+ * @return the notification count of this listener.
+ */
+ public int getCount() {
+ return m_counter;
+ }
+ }
+
+}
diff --git a/ipojo/handler/jmx/jmx-handler-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/jmx/jmx-handler-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/jmx/jmx-handler/changelog.txt b/ipojo/handler/jmx/jmx-handler/changelog.txt
new file mode 100644
index 0000000..87556fc
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/changelog.txt
@@ -0,0 +1,23 @@
+Changes from 1.4.0 to 1.6.0
+---------------------------
+** Improvement
+ * [FELIX-2633] - Rename JMX annotations
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1183] - iPOJO JMX handler doesn't re-throw exceptions
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-828] - iPOJO JMX Handler: the name attribute has not the expected behavior
+ * [FELIX-829] - iPOJO JMX Handler: the sub-element should refer to the handler namespace
+
+Version 1.0.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/jmx/jmx-handler/metadata.xml b/ipojo/handler/jmx/jmx-handler/metadata.xml
new file mode 100644
index 0000000..67b6b38
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/metadata.xml
@@ -0,0 +1,22 @@
+<!--
+ 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.
+-->
+<ipojo>
+<handler classname="org.apache.felix.ipojo.handlers.jmx.MBeanHandler" name="config" namespace="org.apache.felix.ipojo.handlers.jmx" />
+<handler classname="org.apache.felix.ipojo.handlers.jmx.MBeanHandler" name="JMXBean" namespace="org.apache.felix.ipojo.handlers.jmx" />
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/jmx/jmx-handler/obr.xml b/ipojo/handler/jmx/jmx-handler/obr.xml
new file mode 100644
index 0000000..310c385
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/obr.xml
@@ -0,0 +1,30 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="config"/>
+ <p n="namespace" v="org.apache.felix.ipojo.handlers.jmx"/>
+ <p n="type" v="primitive"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="JMXBean"/>
+ <p n="namespace" v="org.apache.felix.ipojo.handlers.jmx"/>
+ <p n="type" v="primitive"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/handler/jmx/jmx-handler/pom.xml b/ipojo/handler/jmx/jmx-handler/pom.xml
new file mode 100644
index 0000000..37636b7
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/pom.xml
@@ -0,0 +1,105 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO JMX Handler</name>
+ <artifactId>org.apache.felix.ipojo.handler.jmx</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+
+ <description>
+ iPOJO extension to expose instances as MBean inside a MBean Server.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/ipojo-jmx-handler.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <version>2.3.7</version>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.handlers.jmx
+ </Private-Package>
+ <Import-Package>
+ org.osgi.framework;version=1.5, *
+ </Import-Package>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO JMX Handler</Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/ipojo-jmx-handler.html
+ </Bundle-DocURL>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <metadata>metadata.xml</metadata>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java
new file mode 100644
index 0000000..d2fe8f2
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanImpl.java
@@ -0,0 +1,408 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.management.Attribute;
+import javax.management.AttributeChangeNotification;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Logger;
+
+/**
+ * This class implements iPOJO DynamicMBean. it builds the dynamic MBean
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DynamicMBeanImpl extends NotificationBroadcasterSupport implements
+ DynamicMBean {
+
+ /**
+ * The instance manager. Used to store the InstanceManager instance.
+ */
+ protected final InstanceManager m_instanceManager;
+
+ /**
+ * The JmxConfigDFieldMap. Stors the data extracted from metadata.xml.
+ */
+ private JmxConfigFieldMap m_configMap;
+
+ /**
+ * The MBeanInfo. The class storing the MBean Informations.
+ */
+ private MBeanInfo m_mBeanInfo;
+
+ /**
+ * The class name. Constant storing the name of the class.
+ */
+ private String m_className = this.getClass().getName();
+
+ /**
+ * The sequence number. Used to calculate unique id to notification.
+ */
+ private int m_sequenceNumber;
+
+ /**
+ * Constructor.
+ *
+ * @param properties the data extracted from metadat.xml file
+ * @param instanceManager the InstanceManager instance
+ */
+ public DynamicMBeanImpl(JmxConfigFieldMap properties,
+ InstanceManager instanceManager) {
+ m_configMap = properties;
+ m_instanceManager = instanceManager;
+ this.buildMBeanInfo();
+ }
+
+ /**
+ * Gets the value of the required attribute.
+ *
+ * @param arg0 the name of required attribute
+ * @throws AttributeNotFoundException if the attribute doesn't exist
+ * @throws MBeanException if something bad occures
+ * @throws ReflectionException if something bad occures
+ * @return the object attribute
+ */
+ public Object getAttribute(String arg0) throws AttributeNotFoundException,
+ MBeanException, ReflectionException {
+ PropertyField attribute = m_configMap.getPropertyFromName(arg0);
+
+ if (attribute == null) {
+ throw new AttributeNotFoundException(arg0 + " not found");
+ } else {
+ return attribute.getValue();
+ }
+ }
+
+ /**
+ * Gets values of required attributes.
+ *
+ * @param attributeNames the names of the required attributes
+ * @return return the list of the attribute
+ */
+ public AttributeList getAttributes(String[] attributeNames) {
+
+ if (attributeNames == null) {
+ throw new IllegalArgumentException(
+ "attributeNames[] cannot be null");
+ }
+
+ AttributeList resultList = new AttributeList();
+ for (int i = 0; i < attributeNames.length; i++) {
+ PropertyField propertyField = (PropertyField) m_configMap
+ .getPropertyFromField((String) attributeNames[i]);
+
+ if (propertyField != null) {
+ resultList.add(new Attribute(attributeNames[i], propertyField
+ .getValue()));
+ }
+ }
+ return resultList;
+ }
+
+ /**
+ * Returns the MBean Class builded.
+ *
+ * @return return MBeanInfo class constructed by buildMBeanInfo
+ */
+ public MBeanInfo getMBeanInfo() {
+ return m_mBeanInfo;
+ }
+
+ /**
+ * Invokes the required method on the targeted POJO.
+ *
+ * @param operationName the name of the method called
+ * @param params the parameters given to the method
+ * @param signature the determine which method called
+ * @return the object return by the method
+ * @throws MBeanException if something bad occures
+ * @throws ReflectionException if something bad occures
+ */
+ public Object invoke(String operationName, Object[] params,
+ String[] signature) throws MBeanException, ReflectionException {
+
+ MethodField method = m_configMap.getMethodFromName(operationName,
+ signature);
+ if (method != null) {
+ MethodMetadata methodCall = method.getMethod();
+ Callback mc = new Callback(methodCall, m_instanceManager);
+ try {
+ return mc.call(params);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException(e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException(e);
+ } catch (InvocationTargetException e) {
+ throw new MBeanException(e);
+ }
+ } else {
+ throw new ReflectionException(new NoSuchMethodException(
+ operationName), "Cannot find the operation " + operationName
+ + " in " + m_className);
+ }
+ }
+
+ /**
+ * Changes specified attribute value.
+ *
+ * @param attribute the attribute with new value to be changed
+ * @throws AttributeNotFoundException if the required attribute was not found
+ * @throws InvalidAttributeValueException if the value is inccorrect type
+ * @throws MBeanException if something bad occures
+ * @throws ReflectionException if something bad occures
+ */
+ public void setAttribute(Attribute attribute)
+ throws AttributeNotFoundException, InvalidAttributeValueException,
+ MBeanException, ReflectionException {
+
+ // Check attribute is not null to avoid NullPointerException later on
+ if (attribute == null) {
+ throw new RuntimeOperationsException(new IllegalArgumentException(
+ "Attribute cannot be null"), "Cannot invoke a setter of "
+ + m_className + " with null attribute");
+ }
+ String name = attribute.getName();
+ Object value = attribute.getValue();
+
+ if (name == null) {
+ throw new RuntimeOperationsException(new IllegalArgumentException(
+ "Attribute name cannot be null"),
+ "Cannot invoke the setter of " + m_className
+ + " with null attribute name");
+ }
+ // Check for a recognized attribute name and call the corresponding
+ // setter
+ //
+
+ PropertyField propertyField = (PropertyField) m_configMap
+ .getPropertyFromName(name);
+ if (propertyField == null) {
+ // unrecognized attribute name:
+ throw new AttributeNotFoundException("Attribute " + name
+ + " not found in " + m_className);
+ }
+ if (!propertyField.isWritable()) {
+ throw new InvalidAttributeValueException("Attribute " + name
+ + " can not be set");
+ }
+
+ if (value == null) {
+ try {
+ m_instanceManager.onSet(null, propertyField.getField(), null);
+ } catch (Exception e) {
+ throw new InvalidAttributeValueException(
+ "Cannot set attribute " + name + " to null");
+ }
+ } else { // if non null value, make sure it is assignable to the
+ // attribute
+// if (true /* TODO type.class.isAssignableFrom(value.getClass()) */) {
+ // propertyField.setValue(value);
+ // setValue(attributeField.getField(),null);
+ m_instanceManager.onSet(null, propertyField.getField(), value);
+// } else {
+// throw new InvalidAttributeValueException(
+// "Cannot set attribute " + name + " to a "
+// + value.getClass().getName()
+// + " object, String expected");
+// }
+ }
+
+ }
+
+ /**
+ * Changes all the attributes value.
+ *
+ * @param attributes the list of attribute value to be changed
+ * @return the list of new attribute
+ */
+ public AttributeList setAttributes(AttributeList attributes) {
+
+ // Check attributes is not null to avoid NullPointerException later on
+ if (attributes == null) {
+ throw new RuntimeOperationsException(new IllegalArgumentException(
+ "AttributeList attributes cannot be null"),
+ "Cannot invoke a setter of " + m_className);
+ }
+ AttributeList resultList = new AttributeList();
+
+ // if attributeNames is empty, nothing more to do
+ if (attributes.isEmpty()) {
+ return resultList;
+ }
+
+ // for each attribute, try to set it and add to the result list if
+ // successful
+ for (Iterator i = attributes.iterator(); i.hasNext();) {
+ Attribute attr = (Attribute) i.next();
+ try {
+ setAttribute(attr);
+ String name = attr.getName();
+ Object value = getAttribute(name);
+ resultList.add(new Attribute(name, value));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return resultList;
+ }
+
+ /**
+ * Builds the MBean information on initialization. This
+ * value doesn't change further.
+ */
+ private void buildMBeanInfo() {
+
+ // generate infos for attributes
+ MBeanAttributeInfo[] dAttributes = null;
+
+ if (m_configMap == null) {
+ return;
+ }
+
+ String dDescription = m_configMap.getDecription();
+
+ if (m_configMap.getProperties() != null) {
+ List < MBeanAttributeInfo > lAttributes = null;
+ lAttributes = new ArrayList < MBeanAttributeInfo >();
+
+ Iterator < PropertyField > iterator = m_configMap.getProperties()
+ .iterator();
+ while (iterator.hasNext()) {
+ PropertyField propertyField = iterator.next();
+ lAttributes.add(new MBeanAttributeInfo(propertyField.getName(),
+ propertyField.getType(), propertyField.getDescription(),
+ propertyField.isReadable(), propertyField.isWritable(),
+ false));
+ }
+ dAttributes = lAttributes
+ .toArray(new MBeanAttributeInfo[lAttributes.size()]);
+ }
+
+ MBeanOperationInfo[] dOperations = null;
+ if (m_configMap.getMethods() != null) {
+
+ List < MBeanOperationInfo > lOperations = new ArrayList < MBeanOperationInfo >();
+
+ Iterator < MethodField[] > iterator = m_configMap.getMethods()
+ .iterator();
+ while (iterator.hasNext()) {
+ MethodField[] method = iterator.next();
+ for (int i = 0; i < method.length; i++) {
+ lOperations.add(new MBeanOperationInfo(method[i].getName(),
+ method[i].getDescription(), method[i].getParams(),
+ method[i].getReturnType(), MBeanOperationInfo.UNKNOWN));
+ }
+ dOperations = lOperations
+ .toArray(new MBeanOperationInfo[lOperations.size()]);
+ }
+ }
+
+ MBeanNotificationInfo[] dNotification = new MBeanNotificationInfo[0];
+ if (m_configMap.getMethods() != null) {
+
+ List < MBeanNotificationInfo > lNotifications = new ArrayList < MBeanNotificationInfo >();
+
+ Iterator < NotificationField > iterator = m_configMap
+ .getNotifications().iterator();
+ while (iterator.hasNext()) {
+ NotificationField notification = iterator
+ .next();
+ lNotifications.add(notification.getNotificationInfo());
+ }
+ dNotification = lNotifications
+ .toArray(new MBeanNotificationInfo[lNotifications.size()]);
+ }
+
+ m_mBeanInfo = new MBeanInfo(this.m_className, dDescription,
+ dAttributes, null, // No constructor
+ dOperations, dNotification);
+ }
+
+ /**
+ * Gets the notification informations (use by JMX).
+ *
+ * @return the structure which describe the notifications
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ MBeanNotificationInfo[] dNotification = new MBeanNotificationInfo[0];
+ if (m_configMap.getMethods() != null) {
+
+ List < MBeanNotificationInfo > lNotifications = new ArrayList < MBeanNotificationInfo >();
+
+ Iterator < NotificationField > iterator = m_configMap
+ .getNotifications().iterator();
+ while (iterator.hasNext()) {
+ NotificationField notification = iterator
+ .next();
+ lNotifications.add(notification.getNotificationInfo());
+ }
+ dNotification = lNotifications
+ .toArray(new MBeanNotificationInfo[lNotifications.size()]);
+ }
+ return dNotification;
+ }
+
+ /**
+ * Sends a notification to a subscriber.
+ *
+ * @param msg the msg to send
+ * @param attributeName the name of the attribute
+ * @param attributeType the type of the attribute
+ * @param oldValue the old value of the attribute
+ * @param newValue the new value of the attribute
+ */
+ public void sendNotification(String msg, String attributeName,
+ String attributeType, Object oldValue, Object newValue) {
+
+ long timeStamp = System.currentTimeMillis();
+
+ if ((newValue == null && oldValue == null)
+ || (newValue != null && newValue.equals(oldValue))) {
+ return;
+ }
+ m_sequenceNumber++;
+ Notification notification = new AttributeChangeNotification(this,
+ m_sequenceNumber, timeStamp, msg, attributeName, attributeType,
+ oldValue, newValue);
+ sendNotification(notification);
+ m_instanceManager.getFactory().getLogger().log(Logger.INFO,
+ "Notification sent");
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanWRegisterImpl.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanWRegisterImpl.java
new file mode 100644
index 0000000..c3c9dd3
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/DynamicMBeanWRegisterImpl.java
@@ -0,0 +1,165 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.util.Callback;
+
+/**
+ * This class implements a 'wide' iPOJO DynamicMBean that can perform actions
+ * before and after its registration and deregistration.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DynamicMBeanWRegisterImpl extends DynamicMBeanImpl implements
+ MBeanRegistration {
+
+ /**
+ * The preRegister method of MBeanRegistration interface.
+ */
+ private MethodMetadata m_preRegisterMeth;
+ /**
+ * The postRegister method of MBeanRegistration interface.
+ */
+ private MethodMetadata m_postRegisterMeth;
+ /**
+ * The preDeregister method of MBeanRegistration interface.
+ */
+ private MethodMetadata m_preDeregisterMeth;
+ /**
+ * The postDeregister method of MBeanRegistration interface.
+ */
+ private MethodMetadata m_postDeregisterMeth;
+ /**
+ * The effective name of the MBean.
+ */
+ private ObjectName m_objName;
+
+ /**
+ * Constructs a new DynamicMBeanWRegisterImpl.
+ *
+ * @param properties the data extracted from the metadata.xml
+ * @param instanceManager the instance manager
+ * @param preRegisterMeth the method to call before MBean registration
+ * @param postRegisterMeth the method to call after MBean registration
+ * @param preDeregisterMeth the method to call before MBean deregistration
+ * @param postDeregisterMeth the method to call after MBean registration
+ */
+ public DynamicMBeanWRegisterImpl(JmxConfigFieldMap properties,
+ InstanceManager instanceManager, MethodMetadata preRegisterMeth,
+ MethodMetadata postRegisterMeth, MethodMetadata preDeregisterMeth,
+ MethodMetadata postDeregisterMeth) {
+ super(properties, instanceManager);
+
+ m_preRegisterMeth = preRegisterMeth;
+ m_postRegisterMeth = postRegisterMeth;
+ m_preDeregisterMeth = preDeregisterMeth;
+ m_postDeregisterMeth = postDeregisterMeth;
+ }
+
+ /**
+ * Returns the MBean name used to register it.
+ *
+ * @return the MBean name used to register it.
+ */
+ public ObjectName getObjectName() {
+ return m_objName;
+ }
+
+ /**
+ * This method is executed before the MBean registration.
+ *
+ * @param server the server on which the MBean will be registered
+ * @param name the name of the MBean to expose
+ * @throws Exception This exception will be caught by the MBean server and re-thrown as an MBeanRegistrationException.
+ * @return the name with which the MBean will be registered
+ */
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ throws Exception {
+ m_objName = (ObjectName) callMethod(m_preRegisterMeth,
+ MBeanHandler.PRE_REGISTER_METH_NAME, new Object[] { server, name });
+ return m_objName;
+ }
+
+ /**
+ * This method is executed after the MBean registration.
+ *
+ * @param registrationDone indicates whether or not the MBean has been successfully registered in the MBean server.
+ */
+ public void postRegister(Boolean registrationDone) {
+ callMethod(m_postRegisterMeth, MBeanHandler.POST_REGISTER_METH_NAME,
+ new Object[] { registrationDone });
+ }
+
+ /**
+ * This method is before after the MBean deregistration.
+ *
+ * @throws Exception This exception will be caught by the MBean server and re-thrown as an MBeanRegistrationException.
+ */
+ public void preDeregister() throws Exception {
+ callMethod(m_preDeregisterMeth, MBeanHandler.PRE_DEREGISTER_METH_NAME,
+ null);
+ }
+
+ /**
+ * This method is executed after the MBean deregistration.
+ */
+ public void postDeregister() {
+ callMethod(m_postDeregisterMeth,
+ MBeanHandler.POST_DEREGISTER_METH_NAME, null);
+ }
+
+ /**
+ * Private method used to execute a given callback.
+ *
+ * @param methodMetadata the metadata description of the callback
+ * @param methodName the name of the callback
+ * @param params the parameters of the callback
+ * @return the object eventually returned by the callback, or null if nothing's returned
+ */
+ private Object callMethod(MethodMetadata methodMetadata, String methodName,
+ Object[] params) {
+ Callback mc = new Callback(methodMetadata, m_instanceManager);
+ try {
+ if ((params == null) || (params.length == 0)) {
+ return mc.call();
+ } else {
+ return mc.call(params);
+ }
+ } catch (NoSuchMethodException e) {
+ // should never happen : method exists
+ System.err.println("No such method : " + methodName);
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ System.err.println("Illegal Access Exception");
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.err.println("Invocation Target Exception");
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXHandlerDescription.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXHandlerDescription.java
new file mode 100644
index 0000000..a5b1955
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXHandlerDescription.java
@@ -0,0 +1,71 @@
+/*
+ * 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.handlers.jmx;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Description of the JMX handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JMXHandlerDescription extends HandlerDescription {
+
+ /**
+ * The referenced handler.
+ */
+ private MBeanHandler m_handler;
+
+ /**
+ * Constructs a new handler description for the given handler.
+ *
+ * @param handler the handler to describe
+ */
+ public JMXHandlerDescription(MBeanHandler handler) {
+ super(handler);
+ m_handler = handler;
+ }
+
+ /**
+ * Gets handler information.
+ *
+ * @return the handler information.
+ */
+ public Element getHandlerInfo() {
+ Element elem = super.getHandlerInfo();
+ elem.addAttribute(new Attribute("registered", Boolean
+ .toString(m_handler.isRegistered())));
+ elem.addAttribute(new Attribute("objectName", m_handler
+ .getUsedObjectName()));
+ if (m_handler.isUsesMOSGi()) {
+ String foundStr = null;
+
+ if (m_handler.isMOSGiExists()) {
+ foundStr = "found";
+ } else {
+ foundStr = "not_found";
+ }
+ elem.addAttribute(new Attribute("mosgi", foundStr));
+ }
+
+ return elem;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java
new file mode 100644
index 0000000..56f436a
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/JmxConfigFieldMap.java
@@ -0,0 +1,297 @@
+/*
+ * 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.handlers.jmx;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * JmxConfigFieldMap : use to store the informations needed to build the Dynamic
+ * MBean.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JmxConfigFieldMap {
+
+ /**
+ * The exposed attributes.
+ */
+ private Map < String, PropertyField > m_properties = new HashMap < String, PropertyField >();
+ /**
+ * The exposed methods.
+ */
+ private Map < String, MethodField[] > m_methods = new HashMap < String, MethodField[] >();
+ /**
+ * The allowed notifications.
+ */
+ private Map < String, NotificationField > m_notifications = new HashMap < String, NotificationField >();
+ /**
+ * The description of the Mbean.
+ */
+ private String m_description;
+
+ /**
+ * Constructor.
+ */
+ public JmxConfigFieldMap() {
+
+ }
+
+ /**
+ * Gets the description of the MBean.
+ *
+ * @return the description of the MBean
+ */
+ public String getDecription() {
+ return m_description;
+ }
+
+ /**
+ * Sets the description of the MBean.
+ *
+ * @param description a String which describes the Mbean
+ */
+ public void setDescription(String description) {
+ this.m_description = description;
+ }
+
+ /**
+ * Adds a new attribute exposed in the Mbean.
+ *
+ * @param name the name of the new property
+ * @param propertyField the field which describes the property
+ */
+ public void addPropertyFromName(String name, PropertyField propertyField) {
+ m_properties.put(name, propertyField);
+ }
+
+ /**
+ * Gets all of the properties exposed.
+ *
+ * @return the collection of all properties
+ */
+ public Collection < PropertyField > getProperties() {
+ if (m_properties != null) {
+ return m_properties.values();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the property by the name.
+ *
+ * @param name the name of the required property
+ * @return the field required or null if is not found
+ */
+ public PropertyField getPropertyFromName(String name) {
+ PropertyField prop = m_properties.get(name);
+ return prop;
+ }
+
+ /**
+ * Gets the property by the field.
+ *
+ * @param field the required field
+ * @return the property by the field
+ */
+ public PropertyField getPropertyFromField(String field) {
+ PropertyField property = null;
+ Iterator < PropertyField > it = m_properties.values().iterator();
+ while (it.hasNext()) {
+ PropertyField p = it.next();
+ if (p.getField().compareTo(field) == 0) {
+ if (property != null) {
+ System.err.println("a field already exists");
+ } else {
+ property = p;
+ }
+ }
+ }
+ return property;
+ }
+
+ /**
+ * Adds a new method descriptor from its name.
+ *
+ * @param name the name of the method
+ * @param methodField the description of the method
+ */
+ public void addMethodFromName(String name, MethodField methodField) {
+ MethodField[] mf;
+ if (!m_methods.containsKey(name)) {
+ mf = new MethodField[1];
+ mf[0] = methodField;
+ } else {
+ MethodField[] temp = m_methods.get(name);
+ mf = new MethodField[temp.length + 1];
+ for (int i = 0; i < temp.length; i++) {
+ mf[i] = temp[i];
+ }
+ mf[temp.length] = methodField;
+ }
+ m_methods.put(name, mf);
+ }
+
+ /**
+ * Adds new methods descriptors from one name. (the method must have the same name but different signature).
+ *
+ * @param name the name of the method
+ * @param methodsField the description of the methods
+ */
+ public void addMethodFromName(String name, MethodField[] methodsField) {
+ MethodField[] mf;
+ if (!m_methods.containsKey(name)) {
+ mf = methodsField;
+ } else {
+ MethodField[] temp = m_methods.get(name);
+ mf = new MethodField[temp.length + methodsField.length];
+ for (int i = 0; i < temp.length; i++) {
+ mf[i] = temp[i];
+ }
+ for (int i = 0; i < methodsField.length; i++) {
+ mf[i + temp.length] = methodsField[i];
+ }
+ }
+ m_methods.put(name, mf);
+ }
+
+ /**
+ * Adds a method from name and erases the older if exists.
+ *
+ * @param name the name of the method
+ * @param methodField the method to be added
+ */
+ public void overrideMethodFromName(String name, MethodField methodField) {
+ MethodField[] mf = new MethodField[1];
+ mf[0] = methodField;
+ m_methods.put(name, mf);
+ }
+
+ /**
+ * Add methods from name and erases the olders if exists.
+ *
+ * @param name the name of the method
+ * @param methodsField the array of methods to be added
+ */
+ public void overrideMethodFromName(String name, MethodField[] methodsField) {
+ m_methods.put(name, methodsField);
+ }
+
+ /**
+ * Returns the method(s) with the given name.
+ *
+ * @param name the name of the methods
+ * @return the list of methods with the given name
+ */
+ public MethodField[] getMethodFromName(String name) {
+ MethodField[] prop = m_methods.get(name);
+ return prop;
+ }
+
+ /**
+ * Gets the method with the good signature.
+ *
+ * @param operationName the name of the method requiered
+ * @param signature the required signature
+ * @return the method which the same signature or null if not found
+ */
+ public MethodField getMethodFromName(String operationName,
+ String[] signature) {
+ MethodField[] methods = m_methods.get(operationName);
+ for (int i = 0; i < methods.length; i++) {
+ if (isSameSignature(signature, methods[i].getSignature())) {
+ return methods[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compares two method signature.
+ *
+ * @param sig1 the first signature
+ * @param sig2 the second signature
+ * @return true if the signature are similar false otherwise
+ */
+ private boolean isSameSignature(String[] sig1, String[] sig2) {
+ if (sig1.length != sig2.length) {
+ return false;
+ } else {
+ for (int i = 0; i < sig1.length; i++) {
+ if (!sig1[i].equals(sig2[i])) {
+ return false;
+ }
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * Returns all methods store.
+ *
+ * @return the collection of methodField[]
+ */
+ public Collection < MethodField[] > getMethods() {
+ if (m_methods != null) {
+ return m_methods.values();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Adds a notification.
+ *
+ * @param name the name of the notification
+ * @param notificationField the field involved with the notification.
+ */
+ public void addNotificationFromName(String name,
+ NotificationField notificationField) {
+ m_notifications.put(name, notificationField);
+ }
+
+ /**
+ * Returns the notification with the given name.
+ *
+ * @param name the name of the notification to return
+ * @return the notification if it exists, {@code null} otherwise
+ */
+ public NotificationField getNotificationFromName(String name) {
+ NotificationField prop = m_notifications.get(name);
+ return prop;
+ }
+
+ /**
+ * Gets all notifications defined.
+ *
+ * @return the collection of NotificationField
+ */
+ public Collection < NotificationField > getNotifications() {
+ if (m_notifications != null) {
+ return m_notifications.values();
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java
new file mode 100644
index 0000000..2258b0e
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MBeanHandler.java
@@ -0,0 +1,664 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.*;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This class implements iPOJO Handler. it builds the dynamic MBean from
+ * metadata.xml and exposes it to the MBean Server.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MBeanHandler extends PrimitiveHandler {
+
+ /**
+ * The name of the MBeanRegistration postDeregister method.
+ */
+ public static final String POST_DEREGISTER_METH_NAME = "postDeregister";
+
+ /**
+ * The name of the MBeanRegistration preDeregister method.
+ */
+ public static final String PRE_DEREGISTER_METH_NAME = "preDeregister";
+
+ /**
+ * The name of the MBeanRegistration postRegister method.
+ */
+ public static final String POST_REGISTER_METH_NAME = "postRegister";
+
+ /**
+ * The name of the MBeanRegistration preRegister method.
+ */
+ public static final String PRE_REGISTER_METH_NAME = "preRegister";
+
+ /**
+ * The name of the global configuration element.
+ */
+ private static final String JMX_CONFIG_ELT = "config";
+
+ /**
+ * The name of the global configuration element.
+ */
+ private static final String JMX_CONFIG_ALT_ELT = "JmxBean";
+
+ /**
+ * The name of the component object full name attribute.
+ */
+ private static final String JMX_OBJ_NAME_ELT = "objectName";
+
+ /**
+ * The name of the component object name domain attribute.
+ */
+ private static final String JMX_OBJ_NAME_DOMAIN_ELT = "domain";
+
+ /**
+ * The name of the component object name attribute.
+ */
+ private static final String JMX_OBJ_NAME_WO_DOMAIN_ELT = "name";
+
+ /**
+ * The name of the attribute indicating if the handler uses MOSGi MBean server.
+ */
+ private static final String JMX_USES_MOSGI_ELT = "usesMOSGi";
+
+ /**
+ * The name of a method element.
+ */
+ private static final String JMX_METHOD_ELT = "method";
+
+ /**
+ * The alternative name of a method element.
+ */
+ private static final String JMX_METHOD_ELT_ALT = "JmxMethod";
+
+ /**
+ * The name of the property or method name attribute.
+ */
+ private static final String JMX_NAME_ELT = "name";
+
+ /**
+ * The name of a method description attribute.
+ */
+ private static final String JMX_DESCRIPTION_ELT = "description";
+
+ /**
+ * The name of a property element.
+ */
+ private static final String JMX_PROPERTY_ELT = "property";
+
+ /**
+ * The alternative name of a property element.
+ */
+ private static final String JMX_PROPERTY_ELT_ALT = "JmxProperty";
+
+ /**
+ * The name of the field attribute.
+ */
+ private static final String JMX_FIELD_ELT = "field";
+
+ /**
+ * The name of the notification attribute.
+ */
+ private static final String JMX_NOTIFICATION_ELT = "notification";
+
+ /**
+ * The name of the rights attribute.
+ */
+ private static final String JMX_RIGHTS_ELT = "rights";
+
+ /**
+ * The instance manager. Used to store the InstanceManager instance.
+ */
+ private InstanceManager m_instanceManager;
+ /**
+ * The service registration. Used to register and unregister the Dynamic MBean.
+ */
+ private ServiceRegistration m_serviceRegistration;
+ /**
+ * Stores data when parsing metadata.xml.
+ */
+ private JmxConfigFieldMap m_jmxConfigFieldMap;
+ /**
+ * Stores the Dynamic MBean.
+ */
+ private DynamicMBeanImpl m_MBean;
+ /**
+ * Constant storing the name of the class.
+ */
+ private String m_namespace = "org.apache.felix.ipojo.handlers.jmx";
+ /**
+ * The flag used to inform if we use the MOSGi framework.
+ */
+ private boolean m_usesMOSGi;
+ /**
+ * The ObjectName used to register the MBean.
+ */
+ private ObjectName m_objectName;
+ /**
+ * The flag used to inform if the MBean is registered.
+ */
+ private boolean m_registered;
+ /**
+ * The ObjectName specified in handler configuration. It can be null.
+ */
+ private String m_completeObjNameElt;
+ /**
+ * The ObjectName without domain specified in handler configuration. It can be null.
+ */
+ private String m_objNameWODomainElt;
+
+ /**
+ * The ObjectName domain specified in handler configuration. It can be null.
+ */
+ private String m_domainElt;
+ /**
+ * The flag informing if the POJO implements the MBeanRegistration interface.
+ */
+ private boolean m_registerCallbacks;
+ /**
+ * The preRegister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_preRegisterMeth;
+ /**
+ * The postRegister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_postRegisterMeth;
+ /**
+ * The preDeregister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_preDeregisterMeth;
+ /**
+ * The postDeregister method of MBeanRegistration interface. It is null if POJO doesn't implement MBeanRegistration interface.
+ */
+ private MethodMetadata m_postDeregisterMeth;
+
+ /**
+ * Constructs the structure JmxConfigFieldMap and the Dynamic Mbean.
+ *
+ * @param metadata the component metadata
+ * @param dict the instance configuration
+ */
+ public void configure(Element metadata, Dictionary dict) {
+
+ PojoMetadata manipulation = getPojoMetadata();
+
+ m_instanceManager = getInstanceManager();
+
+ m_jmxConfigFieldMap = new JmxConfigFieldMap();
+
+ // Build the hashmap
+ Element[] mbeans = metadata.getElements(JMX_CONFIG_ELT, m_namespace);
+ if (mbeans == null || mbeans.length == 0) {
+ mbeans = metadata.getElements(JMX_CONFIG_ALT_ELT, m_namespace);
+ }
+
+ if (mbeans.length != 1) {
+ error("A component must have exactly one " + JMX_CONFIG_ELT + " or " + JMX_CONFIG_ALT_ELT + " element.");
+ error("The JMX handler configuration is ignored.");
+ return;
+ }
+
+ Element mbean = mbeans[0];
+
+ // retrieve kind of MBeanServer to use
+ m_usesMOSGi = Boolean.parseBoolean(mbean.getAttribute(JMX_USES_MOSGI_ELT));
+
+ // retrieve object name
+ m_completeObjNameElt = mbean.getAttribute(JMX_OBJ_NAME_ELT);
+ m_domainElt = mbean.getAttribute(JMX_OBJ_NAME_DOMAIN_ELT);
+ m_objNameWODomainElt = mbean.getAttribute(JMX_OBJ_NAME_WO_DOMAIN_ELT);
+
+ // test if Pojo is interested in registration callbacks
+ m_registerCallbacks = manipulation
+ .isInterfaceImplemented(MBeanRegistration.class.getName());
+ if (m_registerCallbacks) {
+ // don't need to check that methods exist, the pojo implements
+ // MBeanRegistration interface
+ String[] preRegisterParams = { MBeanServer.class.getName(),
+ ObjectName.class.getName() };
+ m_preRegisterMeth = manipulation.getMethod(PRE_REGISTER_METH_NAME,
+ preRegisterParams);
+
+ String[] postRegisterParams = { Boolean.class.getName() };
+ m_postRegisterMeth = manipulation.getMethod(
+ POST_REGISTER_METH_NAME, postRegisterParams);
+
+ m_preDeregisterMeth = manipulation.getMethod(
+ PRE_DEREGISTER_METH_NAME, new String[0]);
+
+ m_postDeregisterMeth = manipulation.getMethod(
+ POST_DEREGISTER_METH_NAME, new String[0]);
+ }
+
+ // set property
+ Element[] attributes = mbean.getElements(JMX_PROPERTY_ELT, m_namespace);
+ Element[] attributesAlt = mbean.getElements(JMX_PROPERTY_ELT_ALT, m_namespace);
+ List<Element> listOfAttributes = new ArrayList<Element>();
+ if (attributes != null) {
+ listOfAttributes.addAll(Arrays.asList(attributes));
+ }
+ if (attributesAlt != null) {
+ listOfAttributes.addAll(Arrays.asList(attributesAlt));
+ }
+
+ Element[] attributesOld = mbeans[0].getElements(JMX_PROPERTY_ELT);
+ if (attributesOld != null) {
+ warn("The JMX property element should use the '" + m_namespace + "' namespace.");
+ listOfAttributes.addAll(Arrays.asList(attributesOld));
+ }
+
+ for (Element attribute : listOfAttributes) {
+ boolean notif = false;
+ String rights;
+ String name;
+ String field = attribute.getAttribute(JMX_FIELD_ELT);
+
+ if (attribute.containsAttribute(JMX_NAME_ELT)) {
+ name = attribute.getAttribute(JMX_NAME_ELT);
+ } else {
+ name = field;
+ }
+ if (attribute.containsAttribute(JMX_RIGHTS_ELT)) {
+ rights = attribute.getAttribute(JMX_RIGHTS_ELT);
+ } else {
+ rights = "r";
+ }
+
+ PropertyField property = new PropertyField(name, field, rights,
+ getTypeFromAttributeField(field, manipulation));
+
+ if (attribute.containsAttribute(JMX_NOTIFICATION_ELT)) {
+ notif = Boolean.parseBoolean(attribute
+ .getAttribute(JMX_NOTIFICATION_ELT));
+ }
+
+ property.setNotifiable(notif);
+
+ if (notif) {
+ // add the new notifiable property in structure
+ NotificationField notification = new NotificationField(
+ name, this.getClass().getName() + "." + field, null);
+ m_jmxConfigFieldMap.addNotificationFromName(name,
+ notification);
+ }
+ m_jmxConfigFieldMap.addPropertyFromName(name, property);
+ getInstanceManager().register(manipulation.getField(field),
+ this);
+ info("property exposed:" + name + " " + field + ":"
+ + getTypeFromAttributeField(field, manipulation) + " "
+ + rights + ", Notif=" + notif);
+ }
+
+ // set methods
+ Element[] methods = mbean.getElements(JMX_METHOD_ELT, m_namespace);
+ Element[] methodsAlt = mbean.getElements(JMX_METHOD_ELT_ALT, m_namespace);
+ List<Element> listOfMethods = new ArrayList<Element>();
+ if (methods != null) {
+ listOfMethods.addAll(Arrays.asList(methods));
+ }
+ if (methodsAlt != null) {
+ listOfMethods.addAll(Arrays.asList(methodsAlt));
+ }
+
+ Element[] methodsOld = mbeans[0].getElements(JMX_PROPERTY_ELT);
+ if (methodsOld != null) {
+ warn("The JMX method element should use the '" + m_namespace + "' namespace.");
+ listOfMethods.addAll(Arrays.asList(methodsOld));
+ }
+
+ for (Element method : listOfMethods) {
+ String name = method.getAttribute(JMX_NAME_ELT);
+ if (name == null) {
+ name = method.getAttribute("method");
+ }
+ String description = null;
+ if (method.containsAttribute(JMX_DESCRIPTION_ELT)) {
+ description = method.getAttribute(JMX_DESCRIPTION_ELT);
+ }
+
+ MethodField[] meth = getMethodsFromName(name, manipulation,
+ description);
+
+ for (int j = 0; j < meth.length; j++) {
+ m_jmxConfigFieldMap.addMethodFromName(name, meth[j]);
+
+ info("method exposed:" + meth[j].getReturnType() + " " + name);
+ }
+ }
+
+ }
+
+ /**
+ * Registers the Dynamic Mbean.
+ */
+ public void start() {
+ // create the corresponding MBean
+ if (m_registerCallbacks) {
+ m_MBean = new DynamicMBeanWRegisterImpl(m_jmxConfigFieldMap,
+ m_instanceManager, m_preRegisterMeth, m_postRegisterMeth,
+ m_preDeregisterMeth, m_postDeregisterMeth);
+ } else {
+ m_MBean = new DynamicMBeanImpl(m_jmxConfigFieldMap,
+ m_instanceManager);
+ }
+
+ if (m_usesMOSGi) {
+ // use whiteboard pattern to register MBean
+
+ if (m_serviceRegistration != null) {
+ m_serviceRegistration.unregister();
+ }
+
+ // Register the ManagedService
+ BundleContext bundleContext = m_instanceManager.getContext();
+ Dictionary<String, String> properties = new Hashtable<String, String>();
+ try {
+ m_objectName = new ObjectName(getObjectNameString());
+
+ properties.put("jmxagent.objectName", m_objectName.toString());
+
+ m_serviceRegistration = bundleContext.registerService(
+ javax.management.DynamicMBean.class.getName(), m_MBean,
+ properties);
+
+ m_registered = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ try {
+ m_objectName = new ObjectName(getObjectNameString());
+ ObjectInstance instance = ManagementFactory
+ .getPlatformMBeanServer().registerMBean(m_MBean,
+ m_objectName);
+
+ // we must retrieve object name used to register the MBean.
+ // It can have been changed by preRegister method of
+ // MBeanRegistration interface.
+ if (m_registerCallbacks) {
+ m_objectName = instance.getObjectName();
+ }
+
+ m_registered = true;
+ } catch (Exception e) {
+ error("Registration of MBean failed.", e);
+ }
+ }
+ }
+
+ /**
+ * Returns the object name of the exposed component.
+ *
+ * @return the object name of the exposed component.
+ */
+ private String getObjectNameString() {
+ if (m_completeObjNameElt != null) {
+ return m_completeObjNameElt;
+ }
+
+ String domain;
+ if (m_domainElt != null) {
+ domain = m_domainElt;
+ } else {
+ domain = getPackageName(m_instanceManager.getClassName());
+ }
+
+ String name = "type=" + m_instanceManager.getClassName() + ",instance="
+ + m_instanceManager.getInstanceName();
+ if (m_objNameWODomainElt != null) {
+ name = "name=" + m_objNameWODomainElt;
+ }
+
+ StringBuffer sb = new StringBuffer();
+ if ((domain != null) && (domain.length() > 0)) {
+ sb.append(domain + ":");
+ }
+ sb.append(name);
+
+ info("Computed Objectname: " + sb.toString());
+
+ return sb.toString();
+ }
+
+ /**
+ * Extracts the package name from of given type.
+ *
+ * @param className the type name.
+ * @return the package name of the given type.
+ */
+ private String getPackageName(String className) {
+ String packageName = "";
+
+ int plotIdx = className.lastIndexOf(".");
+ if (plotIdx != -1) {
+ packageName = className.substring(0, plotIdx);
+ }
+
+ return packageName;
+ }
+
+ /**
+ * Unregisters the Dynamic Mbean.
+ */
+ public void stop() {
+ if (m_usesMOSGi) {
+ if (m_serviceRegistration != null) {
+ m_serviceRegistration.unregister();
+ }
+ } else {
+ if (m_objectName != null) {
+ try {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(
+ m_objectName);
+ } catch (Exception e) {
+ error("Unregistration of MBean failed.", e);
+ }
+ m_objectName = null;
+ }
+ }
+
+ m_MBean = null;
+ m_registered = false;
+ }
+
+ /**
+ * Called when a POJO member is modified externally.
+ *
+ * @param pojo the modified POJO object
+ * @param fieldName the name of the modified field
+ * @param value the new value of the field
+ * @see FieldInterceptor#onSet(Object, String, Object)
+ */
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Check if the field is a configurable property
+
+ PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap
+ .getPropertyFromField(fieldName);
+ if (propertyField != null) {
+ if (propertyField.isNotifiable()) {
+ // TODO should send notif only when value has changed to a value
+ // different than the last one.
+ m_MBean.sendNotification(propertyField.getName() + " changed",
+ propertyField.getName(), propertyField.getType(),
+ propertyField.getValue(), value);
+ }
+ propertyField.setValue(value);
+ }
+ }
+
+ /**
+ * Called when a POJO member is read by the MBean.
+ *
+ * @param pojo the read POJO object.
+ * @param fieldName the name of the modified field
+ * @param value the old value of the field
+ * @return the (injected) value of the field
+ * @see FieldInterceptor#onGet(Object, String, Object)
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+
+ // Check if the field is a configurable property
+ PropertyField propertyField = (PropertyField) m_jmxConfigFieldMap
+ .getPropertyFromField(fieldName);
+ if (propertyField != null) {
+ // Do we have a value to inject ?
+ Object v = propertyField.getValue();
+ if (v == null) {
+ String type = propertyField.getType();
+ if ("boolean".equals(type)) { v = Boolean.FALSE; }
+ else if ("byte".equals(type)) { v = new Byte((byte) 0); }
+ else if ("short".equals(type)) { v = new Short((short) 0); }
+ else if ("int".equals(type)) { v = new Integer(0); }
+ else if ("long".equals(type)) { v = new Long(0); }
+ else if ("float".equals(type)) { v = new Float(0); }
+ else if ("double".equals(type)) { v =new Double(0); }
+ else if ("char".equals(type)) { v = new Character((char) 0); }
+
+ return v;
+ }
+ m_instanceManager.onSet(pojo, fieldName, propertyField.getValue());
+ return propertyField.getValue();
+ }
+ return value;
+ }
+
+ /**
+ * Gets the type from a field name.
+ *
+ * @param fieldRequire the name of the required field
+ * @param manipulation the metadata extracted from metadata.xml file
+ * @return the type of the field or {@code null} if it wasn't found
+ */
+ private static String getTypeFromAttributeField(String fieldRequire,
+ PojoMetadata manipulation) {
+
+ FieldMetadata field = manipulation.getField(fieldRequire);
+ if (field == null) {
+ return null;
+ } else {
+ return FieldMetadata.getReflectionType(field.getFieldType());
+ }
+ }
+
+ /**
+ * Gets all the methods available which get this name.
+ *
+ * @param methodName the name of the required methods
+ * @param manipulation the metadata extract from metadata.xml file
+ * @param description the description which appears in JMX console
+ * @return the array of methods with the right name
+ */
+ private MethodField[] getMethodsFromName(String methodName,
+ PojoMetadata manipulation, String description) {
+
+ MethodMetadata[] methods = manipulation.getMethods(methodName);
+ if (methods.length == 0) {
+ return null;
+ }
+
+ MethodField[] ret = new MethodField[methods.length];
+
+ if (methods.length == 1) {
+ ret[0] = new MethodField(methods[0], description);
+ return ret;
+ } else {
+ for (int i = 0; i < methods.length; i++) {
+ ret[i] = new MethodField(methods[i], description);
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Gets the JMX handler description.
+ *
+ * @return the JMX handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return new JMXHandlerDescription(this);
+ }
+
+ /**
+ * Returns the objectName used to register the MBean. If the MBean is not registered, return an empty string.
+ *
+ * @return the objectName used to register the MBean.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public String getUsedObjectName() {
+ if (m_objectName != null) {
+ return m_objectName.toString();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns true if the MBean is registered.
+ *
+ * @return true if the MBean is registered.
+ */
+ public boolean isRegistered() {
+ return m_registered;
+ }
+
+ /**
+ * Returns true if the MBean must be registered thanks to white board pattern of MOSGi.
+ *
+ * @return {@code true} if the MBean must be registered thanks to white board pattern of MOSGi, false otherwise.
+ */
+ public boolean isUsesMOSGi() {
+ return m_usesMOSGi;
+ }
+
+ /**
+ * Returns true if the MOSGi framework is present on the OSGi platform.
+ *
+ * @return {@code true} if the MOSGi framework is present on the OSGi platform, false otherwise.
+ */
+ public boolean isMOSGiExists() {
+ for (Bundle bundle : m_instanceManager.getContext().getBundles()) {
+ String symbolicName = bundle.getSymbolicName();
+ if ("org.apache.felix.mosgi.jmx.agent".equals(symbolicName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java
new file mode 100644
index 0000000..6ef5b47
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/MethodField.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.handlers.jmx;
+
+import javax.management.MBeanParameterInfo;
+
+import org.apache.felix.ipojo.parser.MethodMetadata;
+
+/**
+ * This class builds a method JMX description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodField {
+
+ /**
+ * Stores the method description.
+ */
+ private String m_description;
+ /**
+ * Stores the method properties.
+ */
+ private MethodMetadata m_method;
+
+ /**
+ * Constructor.
+ *
+ * @param method the method properties
+ * @param description the method description
+ */
+ public MethodField(MethodMetadata method, String description) {
+ this.m_method = method;
+ this.m_description = description;
+
+ }
+
+ /**
+ * Gets the method.
+ * @return the method
+ */
+ public MethodMetadata getMethod() {
+ return m_method;
+ }
+
+ /**
+ * Gets the description.
+ * @return the description
+ */
+ public String getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Gets the name.
+ * @return the name
+ */
+ public String getName() {
+ return m_method.getMethodName();
+ }
+
+ /**
+ * Gets the parameter in JMX format.
+ *
+ * @return info on JMX format
+ */
+ public MBeanParameterInfo[] getParams() {
+ MBeanParameterInfo[] mbean = new MBeanParameterInfo[m_method
+ .getMethodArguments().length];
+ for (int i = 0; i < m_method.getMethodArguments().length; i++) {
+ mbean[i] = new MBeanParameterInfo("arg" + i, m_method
+ .getMethodArguments()[i], null);
+ }
+ return mbean;
+ }
+
+ public String[] getSignature() {
+ return m_method.getMethodArguments();
+ }
+
+ public String getReturnType() {
+ return m_method.getMethodReturn();
+ }
+
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java
new file mode 100644
index 0000000..ac541c4
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/NotificationField.java
@@ -0,0 +1,69 @@
+/*
+ * 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.handlers.jmx;
+
+import javax.management.MBeanNotificationInfo;
+
+/**
+ * This class builds the notification description structure.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class NotificationField {
+ /**
+ * The name of the notification.
+ */
+ private String m_name;
+ /**
+ * The description of the notification.
+ */
+ private String m_description;
+ /**
+ * The field of the notification.
+ */
+ private String m_field;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the notification
+ * @param field the field which send a notification when it is modified
+ * @param description the description which appears in JMX console
+ */
+
+ public NotificationField(String name, String field, String description) {
+ this.m_name = name;
+ this.m_field = field;
+ this.m_description = description;
+ }
+
+ /**
+ * Returns the MBeanNotificationInfo from this class.
+ *
+ * @return the type of the field or {@code null} if it wasn't found
+ */
+ public MBeanNotificationInfo getNotificationInfo() {
+ String[] notificationTypes = new String[1];
+ notificationTypes[0] = m_field;
+ MBeanNotificationInfo mbni = new MBeanNotificationInfo(
+ notificationTypes, m_name, m_description);
+ return mbni;
+ }
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java
new file mode 100644
index 0000000..0712733
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/java/org/apache/felix/ipojo/handlers/jmx/PropertyField.java
@@ -0,0 +1,196 @@
+/*
+ * 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.handlers.jmx;
+
+/**
+ * This class build the notification description structure.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PropertyField {
+
+ /**
+ * The name of the notification.
+ */
+ private String m_name;
+ /**
+ * The name of the notification.
+ */
+ private String m_field;
+ /**
+ * The name of the notification.
+ */
+ private String m_rights;
+ /**
+ * The name of the notification.
+ */
+ private String m_type;
+ /**
+ * The name of the notification.
+ */
+ private Object m_value;
+ /**
+ * The name of the notification.
+ */
+ private boolean m_notification;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the properety
+ * @param field the field which send a notification when it is modified
+ * @param rights the rights of the attribute (ie: 'r' or 'w')
+ * @param type the type of the attribute
+ */
+ public PropertyField(String name, String field, String rights, String type) {
+ this.setName(name);
+ this.setField(field);
+ this.m_type = type;
+ if (isRightsValid(rights)) {
+ this.setRights(rights);
+ } else {
+ this.setRights("r"); // default rights is read only
+ }
+ }
+
+ /**
+ * Returns the field.
+ * @return the field
+ */
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * Modifies the field.
+ * @param field the new field
+ */
+ public void setField(String field) {
+ this.m_field = field;
+ }
+
+ /**
+ * Returns the name.
+ * @return the name
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Modifies the name.
+ * @param name the new name
+ */
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ /**
+ * Returns the rights.
+ * @return the rights
+ */
+ public String getRights() {
+ return m_rights;
+ }
+
+ /**
+ * Modifies the rights.
+ * @param rights the new rights
+ */
+ public void setRights(String rights) {
+ this.m_rights = rights;
+ }
+
+ /**
+ * Returns the value.
+ * @return the value
+ */
+ public Object getValue() {
+ return m_value;
+ }
+
+ /**
+ * Modifies the value.
+ * @param value the new value
+ */
+ public void setValue(Object value) {
+ this.m_value = value;
+ }
+
+ /**
+ * Returns the type.
+ * @return the type
+ */
+ public String getType() {
+ return this.m_type;
+ }
+
+ /**
+ * Returns the description.
+ * @return the description
+ */
+ public String getDescription() {
+ //TODO Implement this method.
+ return null;
+ }
+
+ /**
+ * Returns true if this property field is readable, false otherwise.
+ * @return {@code true} if this property field is readable, {@code false} otherwise.
+ */
+ public boolean isReadable() {
+ return this.getRights().equals("r") || this.getRights().equals("w");
+ }
+
+ /**
+ * Returns true if this property field is writable, false otherwise.
+ * @return {@code true} if this property field is writable, {@code false} otherwise.
+ */
+ public boolean isWritable() {
+ return this.getRights().equals("w");
+ }
+
+ /**
+ * Returns true if this property field is notifiable, false otherwise.
+ * @return {@code true} if this property field is notifiable, {@code false} otherwise.
+ */
+ public boolean isNotifiable() {
+ return this.m_notification;
+ }
+
+ /**
+ * Modify the notifiability of this property field.
+ * @param value the new notifiability of this property field.
+ */
+ public void setNotifiable(boolean value) {
+ this.m_notification = value;
+ }
+
+ /**
+ * Is the rights is valid or not ? (ie = 'r' || 'w').
+ *
+ * @param rights string representing the rights
+ * @return boolean : return {@code true} if rights = 'r' or 'w'
+ */
+ public static boolean isRightsValid(String rights) {
+ return rights != null && (rights.equals("r") || rights.equals("w"));
+ }
+
+}
diff --git a/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd b/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd
new file mode 100644
index 0000000..80152e9
--- /dev/null
+++ b/ipojo/handler/jmx/jmx-handler/src/main/resources/jmx.xsd
@@ -0,0 +1,177 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.jmx"
+ xmlns="org.apache.felix.ipojo.handlers.jmx"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="config" type="JMXType"></xs:element>
+
+ <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: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="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: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: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:annotation>
+ <xs:documentation>Enable or disable attribute change notification sending for this property. If set to "true", 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: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
diff --git a/ipojo/handler/jmx/pom.xml b/ipojo/handler/jmx/pom.xml
new file mode 100644
index 0000000..5329b4b
--- /dev/null
+++ b/ipojo/handler/jmx/pom.xml
@@ -0,0 +1,115 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.jmx-handler-project</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO JMX Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>jmx-handler</module>
+ <module>jmx-handler-it</module>
+ </modules>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>DEPENDENCIES*</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>project</descriptorRef>
+ </descriptorRefs>
+ <!-- we don't want to attach all the assemblies, such as bz2 -->
+ <attach>false</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- only attach the project and bin assemblies, in tar.gz and zip flavors -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.tar.gz
+ </file>
+ <classifier>project</classifier>
+ <type>tar.gz</type>
+ </artifact>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.zip
+ </file>
+ <classifier>project</classifier>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/handler/jmx/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/jmx/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/jmx/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/jmx/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/jmx/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/jmx/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/temporal/changelog.txt b/ipojo/handler/temporal/changelog.txt
new file mode 100644
index 0000000..ce0f55b
--- /dev/null
+++ b/ipojo/handler/temporal/changelog.txt
@@ -0,0 +1,42 @@
+Changes from the 1.6.2 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2438] - Temporal dependencies should use proxies by default
+
+** Improvement
+ * [FELIX-2666] - Rename the temporal handler annotation to avoid collision
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Improvement
+ * [FELIX-2472] - Proxies should throw a runtime exception instead of a null point exception
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-855] - Collection support in iPOJO Temporal Dependencies
+ * [FELIX-860] - Temporal Dependency Proxy injection
+
+Changes from 0.8.1 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-625] - Temporal Dependency improvements (onTimeout policies)
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+
+Version 0.8.1
+-------------
+ * Initial release
diff --git a/ipojo/handler/temporal/pom.xml b/ipojo/handler/temporal/pom.xml
new file mode 100644
index 0000000..4e9132b
--- /dev/null
+++ b/ipojo/handler/temporal/pom.xml
@@ -0,0 +1,115 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.temporal-handler-project</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Temporal Dependency Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>temporal-dependency-handler</module>
+ <module>temporal-dependency-handler-it</module>
+ </modules>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>DEPENDENCIES*</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>project</descriptorRef>
+ </descriptorRefs>
+ <!-- we don't want to attach all the assemblies, such as bz2 -->
+ <attach>false</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- only attach the project and bin assemblies, in tar.gz and zip flavors -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.tar.gz
+ </file>
+ <classifier>project</classifier>
+ <type>tar.gz</type>
+ </artifact>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.zip
+ </file>
+ <classifier>project</classifier>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/handler/temporal/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/temporal/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..f76ce77
--- /dev/null
+++ b/ipojo/handler/temporal/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,17 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
+
diff --git a/ipojo/handler/temporal/src/main/appended-resources/META-INF/LICENSE b/ipojo/handler/temporal/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..c45a1e7
--- /dev/null
+++ b/ipojo/handler/temporal/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Temporal Handler:
+
+The Apache Felix iPOJO Temporal Handler includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/handler/temporal/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/temporal/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..6f2e68f
--- /dev/null
+++ b/ipojo/handler/temporal/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,4 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/pom.xml b/ipojo/handler/temporal/temporal-dependency-handler-it/pom.xml
new file mode 100644
index 0000000..0b34cf8
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/pom.xml
@@ -0,0 +1,390 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
+ <name>Apache Felix iPOJO Temporal Dependency Handler - Integration Test</name>
+ <artifactId>org.apache.felix.ipojo.handler.temporal-it</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.1</url.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.temporal</artifactId>
+ <version>${project.version}</version>
+ <!--
+ The event admin handler depends on an older version of the compendium and core, to avoid issue during
+ tests, we must exclude those artifacts and trust the framework to provide the right / compatible
+ version
+ -->
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude> <!-- Exclude iml files -->
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>regular</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/regular</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>test-all</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>equinox-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>equinox</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/equinox-native</cloneProjectsTo>
+
+ </configuration>
+ </execution>
+ <execution>
+ <id>felix-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/felix-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knopflerfish-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>knopflerfish</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/knopflerfish-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+</project>
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/pom.xml b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/pom.xml
new file mode 100644
index 0000000..af12fda
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.temporal-it</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-temporal-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CheckServiceProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CheckServiceProvider.java
new file mode 100644
index 0000000..404ef35
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CheckServiceProvider.java
@@ -0,0 +1,47 @@
+/*
+ * 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.handler.temporal.components;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService fs;
+
+ public boolean check() {
+ if (fs != null) {
+ return fs.foo();
+ }
+ return false;
+ }
+
+ public Properties getProps() {
+ if (fs != null) {
+ return fs.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CollectionCheckServiceProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CollectionCheckServiceProvider.java
new file mode 100644
index 0000000..853fefc
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/CollectionCheckServiceProvider.java
@@ -0,0 +1,58 @@
+/*
+ * 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.handler.temporal.components;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class CollectionCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private Collection fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ Collection col = fs;
+ if (col != null) {
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ FooService svc = (FooService) it.next();
+ result = result && svc.foo();
+ }
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ Iterator it = fs.iterator();
+ if (it.hasNext()) {
+ FooService svc = (FooService) it.next();
+ return svc.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/FooProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/FooProvider.java
new file mode 100644
index 0000000..b8c1d28
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/FooProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.handler.temporal.components;
+
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class FooProvider implements FooService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/MultipleCheckServiceProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/MultipleCheckServiceProvider.java
new file mode 100644
index 0000000..9affa3f
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/MultipleCheckServiceProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.handler.temporal.components;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService[] fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ FooService[] array = fs;
+ for (int i = 0; array != null && i < array.length; i++) {
+ result = result && array[i].foo();
+ System.out.println("Result : " + result);
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ return fs[0].fooProps();
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/NullableFooProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/NullableFooProvider.java
new file mode 100644
index 0000000..be4d452
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/NullableFooProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.handler.temporal.components;
+
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class NullableFooProvider implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return -1;
+ }
+
+ public int getInt() {
+ return -1;
+ }
+
+ public long getLong() {
+ return -1;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CheckServiceProviderHelper.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CheckServiceProviderHelper.java
new file mode 100755
index 0000000..0a91fbf
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CheckServiceProviderHelper.java
@@ -0,0 +1,64 @@
+/*
+ * 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.handler.temporal.components.proxy;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProviderHelper implements CheckService {
+
+ /**
+ * injected dependency.
+ */
+ private FooService fs;
+
+ public CheckServiceProviderHelper(FooService svc) {
+ fs = svc;
+ }
+
+ public boolean check() {
+ if (fs != null) { // Cannot be null
+ try {
+ return fs.foo();
+ } catch (RuntimeException e) { // Now it's a runtime exception (FELIX-2472)
+ // Can throw a RTE for null policy and for time out
+ if (e.getMessage().equals("No service available")) {
+ // Has detected a null policy.
+ System.out.println(e.getMessage());
+ return false;
+ } else {
+ // Timeout
+ // Propagate the exception
+ throw e;
+ }
+ }
+ }
+ return false;
+ }
+
+ public Properties getProps() {
+ if (fs != null) {
+ return fs.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CollectionCheckServiceProviderHelper.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CollectionCheckServiceProviderHelper.java
new file mode 100644
index 0000000..ad0a7d0
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/CollectionCheckServiceProviderHelper.java
@@ -0,0 +1,62 @@
+/*
+ * 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.handler.temporal.components.proxy;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class CollectionCheckServiceProviderHelper implements CheckService {
+
+ /**
+ * Injected dependency.
+ */
+ private Collection fs;
+
+ public CollectionCheckServiceProviderHelper(Collection col) {
+ fs = col;
+ }
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ Collection col = fs;
+ if (col != null) {
+ Iterator it = col.iterator(); // Get the cached copy
+ while (it != null && it.hasNext()) {
+ FooService svc = (FooService) it.next();
+ result = result && svc.foo();
+ }
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ Iterator it = fs.iterator();
+ if (it.hasNext()) {
+ FooService svc = (FooService) it.next();
+ return svc.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCheckServiceProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCheckServiceProvider.java
new file mode 100755
index 0000000..dcd8240
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCheckServiceProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.handler.temporal.components.proxy;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+
+import java.util.Properties;
+
+public class HelpedCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService fs;
+
+ private CheckServiceProviderHelper helper = new CheckServiceProviderHelper(fs);
+
+ public boolean check() {
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCollectionCheckServiceProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCollectionCheckServiceProvider.java
new file mode 100644
index 0000000..4d40917
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/components/proxy/HelpedCollectionCheckServiceProvider.java
@@ -0,0 +1,43 @@
+/*
+ * 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.handler.temporal.components.proxy;
+
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+
+import java.util.Collection;
+import java.util.Properties;
+
+public class HelpedCollectionCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private Collection fs;
+
+ private CollectionCheckServiceProviderHelper helper = new CollectionCheckServiceProviderHelper(fs);
+
+ public boolean check() {
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/BarService.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/BarService.java
new file mode 100644
index 0000000..a1ff619
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.handler.temporal.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/CheckService.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/CheckService.java
new file mode 100644
index 0000000..abc918a
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.handler.temporal.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ChildInterface.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ChildInterface.java
new file mode 100644
index 0000000..a0cd10e
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ChildInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.handler.temporal.services;
+
+public interface ChildInterface extends ParentInterface1, ParentInterface2 {
+
+ public void processChild();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/FooService.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/FooService.java
new file mode 100644
index 0000000..91c3437
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.handler.temporal.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface1.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface1.java
new file mode 100644
index 0000000..b7e45fe
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface1.java
@@ -0,0 +1,25 @@
+/*
+ * 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.handler.temporal.services;
+
+public interface ParentInterface1 extends ParentParentInterface {
+
+ public void processParent1();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface2.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface2.java
new file mode 100644
index 0000000..fd9af2f
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentInterface2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.handler.temporal.services;
+
+public interface ParentInterface2 {
+
+ public void processParent2();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentParentInterface.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentParentInterface.java
new file mode 100644
index 0000000..aa00405
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/java/org/apache/felix/ipojo/handler/temporal/services/ParentParentInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.handler.temporal.services;
+
+public interface ParentParentInterface {
+
+ public void processParentParent();
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/resources/metadata.xml b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/resources/metadata.xml
new file mode 100644
index 0000000..620fee8
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/main/resources/metadata.xml
@@ -0,0 +1,262 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:temp="org.apache.felix.ipojo.handler.temporal">
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-CheckServiceProvider">
+ <temp:requires field="fs"/>
+ <provides/>
+ </component>
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-CheckServiceProviderUsingTemporal">
+ <temp:temporal field="fs"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-ProxiedCheckServiceProvider">
+ <temp:requires field="fs" proxy="true"/>
+ <provides/>
+ </component>
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-ProxiedCheckServiceProviderUsingTemporal">
+ <temp:temporal field="fs" proxy="true"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-CheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300"/>
+ <provides/>
+ </component>
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-CheckServiceProviderTimeoutUsingTemporal">
+ <temp:temporal field="fs" timeout="300"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-ProxiedCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" timeout="300"/>
+ <provides/>
+ </component>
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-ProxiedCheckServiceProviderTimeoutUsingTemporal">
+ <temp:temporal field="fs" proxy="true" timeout="300"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-MultipleCheckServiceProvider">
+ <temp:requires field="fs" id="foo"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-ColCheckServiceProvider">
+ <temp:requires field="fs" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-ProxiedColCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.FooProvider" name="TEMPORAL-FooProvider">
+ <provides/>
+ </component>
+
+ <!-- Dependencies using nullables -->
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-NullableMultipleCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="nullable"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-NullableColCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="nullable" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-NullableProxiedColCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="nullable" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-NullableCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="nullable"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-NullableProxiedCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="nullable"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-NullableCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="nullable"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-NullableProxiedCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" onTimeout="nullable" timeout="300"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-NullableMultipleCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="nullable"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-NullableColCheckServiceProviderTimeout">
+ <temp:requires field="fs" onTimeout="nullable" timeout="300" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-NullableProxiedColCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" onTimeout="nullable" timeout="300" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using default implementation -->
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-DIMultipleCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-DIColCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-DIProxiedColCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-DICheckServiceProvider">
+ <temp:requires field="fs" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-DIProxiedCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-DICheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-DIProxiedCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" timeout="300" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-DIMultipleCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-DIColCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-DIProxiedColCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" timeout="300" onTimeout="org.apache.felix.ipojo.handler.temporal.components.NullableFooProvider" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using null -->
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-NullMultipleCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-NullColCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="null" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-NullProxiedColCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="null" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-NullCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-NullProxiedCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CheckServiceProvider" name="TEMPORAL-NullCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCheckServiceProvider" name="TEMPORAL-NullProxiedCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" timeout="300" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-NullMultipleCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="null"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-NullColCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="null" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-NullProxiedColCheckServiceProviderTimeout">
+ <temp:requires field="fs" proxy="true" timeout="300" onTimeout="null" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using empty arrays -->
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-EmptyMultipleCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="empty-array"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-EmptyColCheckServiceProvider">
+ <temp:requires field="fs" onTimeout="empty" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-EmptyProxiedColCheckServiceProvider">
+ <temp:requires field="fs" proxy="true" onTimeout="empty" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.MultipleCheckServiceProvider" name="TEMPORAL-EmptyMultipleCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="empty-array"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.CollectionCheckServiceProvider" name="TEMPORAL-EmptyColCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" onTimeout="empty" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.temporal.components.proxy.HelpedCollectionCheckServiceProvider" name="TEMPORAL-EmptyProxiedColCheckServiceProviderTimeout">
+ <temp:requires field="fs" timeout="300" proxy="true" onTimeout="empty" specification="org.apache.felix.ipojo.handler.temporal.services.FooService"/>
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/Common.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/Common.java
new file mode 100644
index 0000000..a6b32af
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/Common.java
@@ -0,0 +1,40 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.ops4j.pax.exam.Option;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.temporal")
+ .versionAsInProject()
+ };
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DefaultImplementationTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DefaultImplementationTest.java
new file mode 100644
index 0000000..42bc9b3
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DefaultImplementationTest.java
@@ -0,0 +1,535 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class DefaultImplementationTest extends Common {
+
+ @Test
+ public void testDefaultImplementation() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DICheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDefaultImplementationWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDefaultImplementationTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DICheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDefaultImplementationTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DICheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIProxiedCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDefaultImplementationMultipleTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDefaultImplementationCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDefaultImplementationProxiedCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-DIProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained DI will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained DI will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnProxiedCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained DI will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayTest.java
new file mode 100644
index 0000000..0c15b65
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayTest.java
@@ -0,0 +1,494 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class DelayTest extends Common {
+
+ @Test
+ public void testDelay() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ assertNull("No FooService", osgiHelper.getServiceReference(FooService.class.getName(), null));
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay (" + (end - begin) + ")", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 4000);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 4000);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testSetTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testSetTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnProxiedCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayedProvider.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayedProvider.java
new file mode 100644
index 0000000..ba65c0a
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/DelayedProvider.java
@@ -0,0 +1,71 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+
+public class DelayedProvider implements Runnable {
+
+
+ public static final long DELAY = 1000;
+ ComponentInstance instance;
+ long delay = DELAY;
+ Thread thread;
+
+ public DelayedProvider(ComponentInstance ci) {
+ instance =ci;
+ }
+
+ public DelayedProvider(ComponentInstance ci, long time) {
+ instance =ci;
+ delay = time;
+ }
+
+ public void start() {
+ thread = new Thread(this);
+ thread.start();
+ }
+
+ public void stop() {
+ if (thread != null) {
+ thread.interrupt();
+ }
+ }
+
+ public void run() {
+ System.out.println("Start sleeping for " + delay);
+ long begin = System.currentTimeMillis();
+ try {
+ Thread.sleep(delay);
+ long end = System.currentTimeMillis();
+ if (end - begin < delay) {
+ // Wait for the remaining time
+ Thread.sleep(delay - (end - begin));
+ }
+ } catch (InterruptedException e) {
+ System.out.println("Interrupted ...");
+ return;
+ }
+ System.out.println("Wakeup");
+ thread = null;
+ instance.start();
+ System.out.println(instance.getInstanceName() + " started");
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/EmptyTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/EmptyTest.java
new file mode 100755
index 0000000..1d33034
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/EmptyTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class EmptyTest extends Common {
+
+ @Test
+ public void testEmptyArrayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testEmptyCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testEmptyProxiedCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyMultipleCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnProxiedCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-EmptyProxiedColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/FilterTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/FilterTest.java
new file mode 100644
index 0000000..ddbc70a
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/FilterTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Checks <tt>requires.filter</tt>, <tt>temporal.filter</tt>, <tt>temporal.from</tt> and
+ * <tt>requires.from</tt> attributes.
+ */
+public class FilterTest extends Common {
+
+ /**
+ * Checks <tt>temporal.filter</tt> with dependency id.
+ * The filter is made to get only one provider.
+ */
+ @Test
+ public void testWithTemporalFilters() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+
+ Dictionary configuration = new Hashtable();
+ String un = "under-1";
+ configuration.put("instance.name", un);
+ Dictionary filter = new Hashtable();
+ filter.put("foo", "(instance.name=provider2)");
+ configuration.put("temporal.filters", filter);
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider",
+ configuration);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ /**
+ * Checks <tt>requires.filter</tt> with dependency id.
+ * The filter is made to get only one provider.
+ */
+ @Test
+ public void testWithRequireFilters() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+
+ Dictionary configuration = new Hashtable();
+ String un = "under-1";
+ configuration.put("instance.name", un);
+ Dictionary filter = new Hashtable();
+ filter.put("foo", "(instance.name=provider2)");
+ configuration.put("requires.filters", filter);
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider", configuration);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ /**
+ * Checks <tt>temporal.from</tt> with dependency id.
+ * The filter is made to get only one specific provider.
+ */
+ @Test
+ public void testWithTemporalFrom() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+
+ Dictionary configuration = new Hashtable();
+ String un = "under-1";
+ configuration.put("instance.name", un);
+ Dictionary filter = new Hashtable();
+ filter.put("foo", "provider2");
+ configuration.put("temporal.from", filter);
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider", configuration);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ /**
+ * Checks <tt>requires.from</tt> with dependency id.
+ * The filter is made to get only one specific provider.
+ */
+ @Test
+ public void testWithRequiresFrom() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+
+ Dictionary configuration = new Hashtable();
+ String un = "under-1";
+ configuration.put("instance.name", un);
+ Dictionary filter = new Hashtable();
+ filter.put("foo", "provider2");
+ configuration.put("requires.from", filter);
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider", configuration);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NoDelayTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NoDelayTest.java
new file mode 100644
index 0000000..600de6c
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NoDelayTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class NoDelayTest extends Common {
+
+ @Test
+ public void testNoDelay() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProvider", un);
+ assertNotNull("Check creation", under);
+ assertNotNull("Check provider creation", prov);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNoDelayWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProvider", un);
+ assertNotNull("Check creation", under);
+ assertNotNull("Check provider creation", prov);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testMultipleNoDelay() {
+ String prov1 = "provider-1";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov1);
+ String un = "under-2";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-MultipleCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov1);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ provider1.stop();
+ provider1.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testCollectionNoDelay() {
+ String prov1 = "provider-1";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov1);
+ String un = "under-2";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov1);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ provider1.stop();
+ provider1.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testProxiedCollectionNoDelay() {
+ String prov1 = "provider-1";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov1);
+ String un = "under-2";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedColCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov1);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ provider1.stop();
+ provider1.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullTest.java
new file mode 100644
index 0000000..289ed35
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullTest.java
@@ -0,0 +1,536 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class NullTest extends Common {
+
+ @Test
+ public void testNull() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A null was expected ...");
+ }
+ assertFalse("Check null", res); // Return false when the foo service is null.
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A null was expected ...");
+ }
+ assertFalse("Check null", res); // Return false when the foo service is null.
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullProxiedCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullMultipleTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A null was expected ...");
+ }
+ assertTrue("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testNullCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A null was expected ...");
+ }
+ assertTrue("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testNullProxiedCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A null was expected ... : " + e.getMessage());
+ e.printStackTrace();
+ }
+ assertTrue("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnProxiedCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullableTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullableTest.java
new file mode 100644
index 0000000..ca3c1d2
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/NullableTest.java
@@ -0,0 +1,535 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class NullableTest extends Common {
+
+ @Test
+ public void testNullable() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullableTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullableWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullableTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testNullableMultipleTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testNullableCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testNullableProxiedCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnProxiedCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-NullableProxiedColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertFalse("Check invocation - 3", cs.check()); // Will return false as the contained nullable will return false to the foo method.
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/TemporalTest.java b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/TemporalTest.java
new file mode 100644
index 0000000..87d6acf
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/it/temporal-it/src/test/java/org/apache/felix/ipojo/handler/temporal/test/TemporalTest.java
@@ -0,0 +1,345 @@
+/*
+ * 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.handler.temporal.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.temporal.services.CheckService;
+import org.apache.felix.ipojo.handler.temporal.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class TemporalTest extends Common {
+
+ @Test
+ public void testDelay() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ assertNull("No FooService", osgiHelper.getServiceReference(FooService.class.getName(), null));
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay (" + (end - begin) + ")", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 4000);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 4000);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderTimeoutUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderTimeoutUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testSetTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-CheckServiceProviderTimeoutUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testSetTimeoutWithProxy() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("TEMPORAL-FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("TEMPORAL-ProxiedCheckServiceProviderTimeoutUsingTemporal", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/temporal/temporal-dependency-handler-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/changelog.txt b/ipojo/handler/temporal/temporal-dependency-handler/changelog.txt
new file mode 100644
index 0000000..ce0f55b
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/changelog.txt
@@ -0,0 +1,42 @@
+Changes from the 1.6.2 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2438] - Temporal dependencies should use proxies by default
+
+** Improvement
+ * [FELIX-2666] - Rename the temporal handler annotation to avoid collision
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Improvement
+ * [FELIX-2472] - Proxies should throw a runtime exception instead of a null point exception
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-855] - Collection support in iPOJO Temporal Dependencies
+ * [FELIX-860] - Temporal Dependency Proxy injection
+
+Changes from 0.8.1 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-625] - Temporal Dependency improvements (onTimeout policies)
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+
+Version 0.8.1
+-------------
+ * Initial release
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/obr.xml b/ipojo/handler/temporal/temporal-dependency-handler/obr.xml
new file mode 100644
index 0000000..ef50806
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/obr.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="requires"/>
+ <p n="namespace" v="org.apache.felix.ipojo.handler.temporal"/>
+ <p n="type" v="primitive"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/pom.xml b/ipojo/handler/temporal/temporal-dependency-handler/pom.xml
new file mode 100644
index 0000000..166ea07
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/pom.xml
@@ -0,0 +1,122 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <artifactId>org.apache.felix.ipojo.handler.temporal</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Temporal Service Dependency Handler</name>
+
+ <description>
+ iPOJO extension to inject temporal service dependencies.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/temporal-service-dependency.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>5.0.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ org.apache.felix.ipojo.handler.temporal;-split-package:=merge-first,
+ org.objectweb.asm;-split-package:=merge-last
+ </Private-Package>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>
+ org.apache.felix.ipojo;version=1.10.0,
+ !org.objectweb.asm.tree, *
+ </Import-Package>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Temporal Dependency Handler
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/temporal-service-dependency.html
+ </Bundle-DocURL>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.10.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..f76ce77
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,17 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
+
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/LICENSE b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..c45a1e7
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Temporal Handler:
+
+The Apache Felix iPOJO Temporal Handler includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..6f2e68f
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,4 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
new file mode 100644
index 0000000..a3fcd69
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
@@ -0,0 +1,183 @@
+/*
+ * 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.handler.temporal;
+
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Generates proxy class delegating operation invocations thanks to a
+ * a temporal dependency.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProxyGenerator implements Opcodes {
+
+ /**
+ * The temporal dependency name.
+ */
+ private static final String DEPENDENCY = "m_dependency";
+
+ /**
+ * The Temporal Dependency descriptor.
+ */
+ private static final String DEPENDENCY_DESC = Type.getDescriptor(TemporalDependency.class);
+
+ /**
+ * Temporal dependency internal class name.
+ */
+ private static final String TEMPORAL_DEPENDENCY = "org/apache/felix/ipojo/handler/temporal/TemporalDependency";
+
+ /**
+ * Gets the internal names of the given class objects.
+ * @param classes the classes
+ * @return the array containing internal names of the given class array.
+ */
+ private static String[] getInternalClassNames(Class[] classes) {
+ final String[] names = new String[classes.length];
+ for (int i = 0; i < names.length; i++) {
+ names[i] = Type.getInternalName(classes[i]);
+ }
+ return names;
+ }
+
+ /**
+ * Generates a proxy class.
+ * @param spec the proxied service specification
+ * @return the byte[] for the generated proxy class.
+ */
+ public static byte[] dumpProxy(Class spec) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ String internalClassName = Type.getInternalName(spec); // Specification class internal name.
+ String[] itfs = new String[] {internalClassName}; // Implemented interface.
+ String className = internalClassName + "$$Proxy"; // Unique name.
+ Method[] methods = spec.getMethods(); // Method to delegate
+
+ cw.visit(Opcodes.V1_3, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, className, null, "java/lang/Object", itfs);
+ addDependencyField(cw);
+ generateConstructor(cw, className);
+
+ // For each method, create the delegator code.
+ for (int i = 0; i < methods.length; i++) {
+ if ((methods[i].getModifiers() & (Modifier.STATIC | Modifier.FINAL)) == 0) {
+ generateDelegator(cw, methods[i], className, internalClassName);
+ }
+ }
+
+ cw.visitEnd();
+
+ return cw.toByteArray();
+
+ }
+
+ /**
+ * Generates a delegated method.
+ * @param cw the class writer
+ * @param method the method object to delegate
+ * @param className the generated class name
+ * @param itfName the internal specification class name
+ */
+ private static void generateDelegator(ClassWriter cw, Method method,
+ String className, String itfName) {
+ String methodName = method.getName();
+ String desc = Type.getMethodDescriptor(method);
+ String[] exceptions = getInternalClassNames(method.getExceptionTypes());
+ int modifiers = method.getModifiers()
+ & ~(Modifier.ABSTRACT | Modifier.NATIVE | Modifier.SYNCHRONIZED);
+ Type[] types = Type.getArgumentTypes(method);
+
+ int freeRoom = 1;
+ for (int t = 0; t < types.length; t++) {
+ freeRoom = freeRoom + types[t].getSize();
+ }
+
+ MethodVisitor mv = cw.visitMethod(modifiers, methodName, desc, null,
+ exceptions);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // The temporal dependency is on the stack.
+ mv.visitMethodInsn(INVOKEVIRTUAL, TEMPORAL_DEPENDENCY, "getService", // Call getService
+ "()Ljava/lang/Object;"); // The service object is on the stack.
+ int varSvc = freeRoom;
+ freeRoom = freeRoom + 1; // Object Reference.
+ mv.visitVarInsn(ASTORE, varSvc); // Store the service object.
+
+ // Invoke the method on the service object.
+ mv.visitVarInsn(ALOAD, varSvc);
+ // Push argument on the stack.
+ int i = 1; // Arguments. (non static method)
+ for (int t = 0; t < types.length; t++) {
+ mv.visitVarInsn(types[t].getOpcode(ILOAD), i);
+ i = i + types[t].getSize();
+ }
+ // Invocation
+ mv.visitMethodInsn(INVOKEINTERFACE, itfName, methodName, desc);
+
+ // Return the result
+ Type returnType = Type.getReturnType(desc);
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+ } else {
+ mv.visitInsn(RETURN);
+ }
+
+ // End of the method.
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generates the constructors. The constructor receives a temporal dependency
+ * and set the {@link ProxyGenerator#DEPENDENCY} field.
+ * @param cw the class writer
+ * @param className the generated class name.
+ */
+ private static void generateConstructor(ClassWriter cw, String className) {
+ MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", '(' + DEPENDENCY_DESC + ")V", null, null);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0); // Load this
+ mv.visitInsn(DUP); // Dup
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); // Call super
+ mv.visitVarInsn(ALOAD, 1); // Load the argument
+ mv.visitFieldInsn(PUTFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // Assign the dependency field
+ mv.visitInsn(RETURN); // Return void
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Adds the temporal dependency field {@link ProxyGenerator#DEPENDENCY}.
+ * @param cw the class writer
+ */
+ private static void addDependencyField(ClassWriter cw) {
+ cw.visitField(Opcodes.ACC_FINAL, DEPENDENCY, DEPENDENCY_DESC, null, null);
+ cw.visitEnd();
+ }
+
+
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceCollection.java b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceCollection.java
new file mode 100644
index 0000000..3369b59
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceCollection.java
@@ -0,0 +1,334 @@
+/*
+ * 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.handler.temporal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+* Maintains a service object collection.
+* This collection wrap the temporal dependency to be accessible from a
+* {@link Collection}, that can be passed to helper objects (Collaborators).
+*
+* The onTimeout policies are executed when the {@link Collection#iterator()},
+* {@link Collection#toArray(Object[])} and {@link Collection#toArray()} methods
+* are called.
+*
+* The {@link Collection#iterator()} method returns an {@link Iterator} iterating
+* on a cached copy of available service objects. In the case that there are no
+* available services when the timeout is reached, the policies act as follows:
+* <ul>
+* <li>'null' returns a null iterator</li>
+* <li>'nullable' and default-implementation returns an iterator iterating on one object (the
+* nullable or default-implementation object</li>
+* <li>'empty' returns an empty iterator.</li>
+* <li>'no policy' throws runtime exception</li>
+* </ul>
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+public class ServiceCollection implements Collection {
+
+ /**
+ * The wrapped temporal dependencies.
+ */
+ private TemporalDependency m_dependency;
+
+ /**
+ * Creates a Service Collection.
+ * @param dep the wrapped temporal dependencies
+ */
+ public ServiceCollection(TemporalDependency dep) {
+ m_dependency = dep;
+ }
+
+ /**
+ * Unsupported method.
+ * @param o an object
+ * @return N/A
+ * @see java.util.Collection#add(java.lang.Object)
+ */
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ * @param c an object
+ * @return N/A
+ * @see java.util.Collection#addAll(java.util.Collection)
+ */
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ * @see java.util.Collection#clear()
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Checks if the wrapped temporal dependencies has always access to the
+ * given service object.The method allows knowing if the provider returning the
+ * service object has leaved.
+ * @param o the service object
+ * @return <code>true</code> if the object is still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean contains(Object o) {
+ return getAvailableObjects().contains(o);
+ }
+
+ /**
+ * Checks if the wrapped temporal dependencies has always access to the
+ * given service objects.The method allows knowing if providers returning the
+ * service objects have leaved.
+ * @param c the set of service object
+ * @return <code>true</code> if the objects are still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean containsAll(Collection c) {
+ return getAvailableObjects().containsAll(c);
+ }
+
+ /**
+ * Checks if at least one provider matching with the dependency
+ * is available.
+ * @return <code>true</code> if one provider or more satisfying the
+ * dependency are available. Otherwise, returns <code>false</code>
+ * @see java.util.Collection#isEmpty()
+ */
+ public boolean isEmpty() {
+ return m_dependency.getSize() == 0;
+ }
+
+ /**
+ * Helper method creating a list of available service objects.
+ * @return the list of available service objects.
+ */
+ private List getAvailableObjects() {
+ List list = new ArrayList();
+ ServiceReference[] refs = m_dependency.getServiceReferences();
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ list.add(m_dependency.getService(refs[i]));
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Gets an iterator on the actual list of available service objects.
+ * This method applies on timeout policies is no services are
+ * available after the timeout.
+ * The returned iterator iterates on a cached copy of the service
+ * objects.
+ * @return a iterator giving access to service objects.
+ * @see java.util.Collection#iterator()
+ */
+ public Iterator iterator() {
+ ServiceReference[] refs = m_dependency.getServiceReferences();
+ if (refs != null) {
+ // Immediate return.
+ return new ServiceIterator(refs); // Create the service iterator with the service reference list.
+ } else {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+ synchronized (this) {
+ while (m_dependency.getServiceReference() == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_dependency.getTimeout();
+ }
+ }
+ }
+ // Check
+ if (exhausted) {
+ Object oto = m_dependency.onTimeout(); // Throws the RuntimeException
+ if (oto == null) { // If null, return null
+ return null;
+ } else {
+ // oto is an instance of collection containing either empty or with only one element
+ return new ServiceIterator((Collection) oto);
+ }
+ } else {
+ refs = m_dependency.getServiceReferences();
+ return new ServiceIterator(refs);
+ }
+ }
+
+
+ }
+
+ /**
+ * Unsupported method.
+ * @param o a object
+ * @return N/A
+ * @see java.util.Collection#remove(java.lang.Object)
+ */
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ *Unsupported method.
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Gets the number of available providers.
+ * @return the number of matching service providers.
+ * @see java.util.Collection#size()
+ */
+ public int size() {
+ return m_dependency.getSize();
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ * @return a array containing available service objects.
+ * depending on the timeout policy, this array can also be <code>null</code>,
+ * be empty, or can contain only one element (a default-implementation
+ * object, or a nullable object).
+ * @see java.util.Collection#toArray()
+ */
+ public Object[] toArray() {
+ return toArray(new Object[0]);
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ * @param a the array into which the elements of this collection
+ * are to be stored, if it is big enough; otherwise, a new array
+ * of the same runtime type is allocated for this purpose.
+ * @return a array containing available service objects.
+ * depending on the timeout policy, this array can also be <code>null</code>,
+ * be empty, or can contain only one element (a default-implementation
+ * object, or a nullable object).
+ * @see java.util.Collection#toArray(java.lang.Object[])
+ */
+ public Object[] toArray(Object[] a) {
+ Iterator it = iterator(); // Can throw an exception.
+ if (it == null) {
+ return null;
+ }
+ // Else we get an iterator.
+ List list = new ArrayList(size());
+ while (it.hasNext()) {
+ list.add(it.next());
+ }
+ return list.toArray(a);
+ }
+
+ /**
+ * Iterator on a set of service objects.
+ * This iterator iterates on a cached copy of service objects.
+ */
+ private final class ServiceIterator implements Iterator {
+
+ /**
+ * Underlying iterator.
+ */
+ private Iterator m_iterator;
+
+ /**
+ * Creates a Service Iterator iterating
+ * on the given set of providers.
+ * @param refs the available service providers
+ */
+ private ServiceIterator(ServiceReference[] refs) {
+ List objects = new ArrayList(refs.length);
+ for (int i = 0; i < refs.length; i++) {
+ objects.add(m_dependency.getService(refs[i]));
+ }
+ m_iterator = objects.iterator();
+ }
+
+ /**
+ * Creates a Service Iterator iterating
+ * on service object contained in the given
+ * collection.
+ * @param col a collection containing service objects.
+ */
+ private ServiceIterator(Collection col) {
+ m_iterator = col.iterator();
+ }
+
+ /**
+ * Returns <code>true</code> if the iteration has
+ * more service objects.
+ * @return <code>true</code> if the iterator has more elements.
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return m_iterator.hasNext();
+ }
+
+ /**
+ * Returns the next service objects in the iteration.
+ * @return the next service object in the iteration.
+ * @see java.util.Iterator#next()
+ */
+ public Object next() {
+ return m_iterator.next();
+ }
+
+ /**
+ * Unsupported operation.
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
new file mode 100644
index 0000000..70184c9
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
@@ -0,0 +1,77 @@
+/*
+ * 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.handler.temporal;
+
+
+/**
+ * Object managing thread local copy of required services.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceUsage extends ThreadLocal {
+
+ /**
+ * Structure contained in the Thread Local.
+ */
+ public static class Usage {
+
+ /**
+ * Stack Size.
+ */
+ int m_stack = 0;
+ /**
+ * Object to inject.
+ */
+ Object m_object;
+
+ /**
+ * Increment the stack level.
+ */
+ public void inc() {
+ m_stack++;
+ }
+
+ /**
+ * Decrement the stack level.
+ * @return true if the stack is 0 after the decrement.
+ */
+ public boolean dec() {
+ m_stack--;
+ return m_stack == 0;
+ }
+
+ /**
+ * Clear the service object array.
+ */
+ public void clear() {
+ m_object = null;
+ }
+
+ }
+
+ /**
+ * Initialize the cached object.
+ * @return an empty Usage object.
+ * @see java.lang.ThreadLocal#initialValue()
+ */
+ public Object initialValue() {
+ return new Usage();
+ }
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
new file mode 100644
index 0000000..49ea111
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
@@ -0,0 +1,555 @@
+/*
+ * 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.handler.temporal;
+
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.MethodInterceptor;
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.handler.temporal.ServiceUsage.Usage;
+import org.apache.felix.ipojo.handlers.dependency.NullableObject;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Temporal dependency. A temporal dependency waits (block) for the availability
+ * of the service. If no provider arrives in the specified among of time, a
+ * runtime exception is thrown.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TemporalDependency extends DependencyModel implements
+ FieldInterceptor, MethodInterceptor {
+
+ /**
+ * The timeout.
+ */
+ private long m_timeout;
+
+ /**
+ * The default implementation.
+ */
+ private String m_di;
+
+ /**
+ * The {@link Nullable} object or Default-Implementation instance if used.
+ */
+ private Object m_nullableObject;
+
+ /**
+ * The handler managing this dependency.
+ */
+ private PrimitiveHandler m_handler;
+
+ /**
+ * The timeout policy. Null injects null, {@link Nullable} injects a nullable object or
+ * an array with a nullable object, Default-Implementation injects an object
+ * created from the specified injected implementation or an array with it
+ * Empty array inject an empty array (must be an aggregate dependency) No
+ * policy (0) throw a runtime exception when the timeout occurs *
+ */
+ private int m_policy;
+
+ /**
+ * The dependency is injected as a collection.
+ * The field must be of the {@link Collection} type
+ */
+ private boolean m_collection;
+
+ /**
+ * Enables the proxy mode.
+ */
+ private boolean m_proxy;
+
+ /**
+ * Service Usage (Thread Local).
+ */
+ private ServiceUsage m_usage;
+
+ /**
+ * The proxy object.
+ * This field is used for scalar proxied temporal dependency.
+ */
+ private Object m_proxyObject;
+
+
+ /**
+ * Creates a temporal dependency.
+ * @param spec the service specification
+ * @param agg is the dependency aggregate ?
+ * @param collection the dependency field is a collection
+ * @param proxy enable the proxy-mode
+ * @param filter the LDAP filter
+ * @param context service context
+ * @param timeout timeout
+ * @param handler Handler managing this dependency
+ * @param defaultImpl class used as default-implementation
+ * @param policy onTimeout policy
+ */
+ public TemporalDependency(Class spec, boolean agg, boolean collection, boolean proxy, Filter filter,
+ BundleContext context, long timeout, int policy,
+ String defaultImpl, TemporalHandler handler) {
+ super(spec, agg, true, filter, null,
+ DependencyModel.DYNAMIC_BINDING_POLICY, context, handler, handler.getInstanceManager());
+ m_di = defaultImpl;
+ m_policy = policy;
+ m_timeout = timeout;
+ m_handler = handler;
+ m_collection = collection;
+ m_proxy = proxy;
+ if (! proxy) { // No proxy => initialize the Thread local.
+ m_usage = new ServiceUsage();
+ } else if (proxy && ! agg) { // Scalar proxy => Create the proxy.
+ ProxyFactory proxyFactory = new ProxyFactory(this.getClass().getClassLoader());
+ m_proxyObject = proxyFactory.getProxy(getSpecification(), this);
+ }
+ }
+
+ /**
+ * The dependency has been reconfigured.
+ * @param arg0 new service references
+ * @param arg1 old service references
+ * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[],
+ * org.osgi.framework.ServiceReference[])
+ */
+ public void onDependencyReconfiguration(ServiceReference[] arg0,
+ ServiceReference[] arg1) {
+ throw new UnsupportedOperationException(
+ "Reconfiguration not yet supported");
+ }
+
+ /**
+ * A provider arrives.
+ * @param ref service reference of the new provider.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
+ */
+ public synchronized void onServiceArrival(ServiceReference ref) {
+ // Notify if a thread is waiting.
+ notifyAll();
+ }
+
+ /**
+ * A provider leaves.
+ * @param arg0 leaving service references.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceDeparture(ServiceReference arg0) { }
+
+ /**
+ * A provider is modified.
+ * @param arg0 leaving service references.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceModification(ServiceReference arg0) { }
+
+ /**
+ * The code require a value of the monitored field. If providers are
+ * available, the method return service object(s) immediately. Else, the
+ * thread is blocked until an arrival. If no provider arrives during the
+ * among of time specified, the method throws a Runtime Exception.
+ * @param arg0 POJO instance asking for the service
+ * @param arg1 field name
+ * @param arg2 previous value
+ * @return the object to inject.
+ * @see org.apache.felix.ipojo.FieldInterceptor#onGet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public synchronized Object onGet(Object arg0, String arg1, Object arg2) {
+ // Check if the Thread local as a value
+ if (! m_proxy) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ return usage.m_object;
+ }
+ }
+
+ ServiceReference[] refs = getServiceReferences();
+ if (refs != null) {
+ // Immediate return.
+ return getServiceObjects(refs);
+ } else {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+ synchronized (this) {
+ while (getServiceReference() == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_timeout;
+ }
+ }
+ }
+ // Check
+ if (exhausted) {
+ return onTimeout();
+ } else {
+ refs = getServiceReferences();
+ return getServiceObjects(refs);
+ }
+ }
+ }
+
+ /**
+ * A POJO method will be invoked.
+ * @param pojo : Pojo object
+ * @param method : called method
+ * @param args : arguments
+ * @see org.apache.felix.ipojo.MethodInterceptor#onEntry(java.lang.Object, java.lang.reflect.Member, java.lang.Object[])
+ */
+ public void onEntry(Object pojo, Member method, Object[] args) {
+ if (m_usage != null) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ usage.inc();
+ m_usage.set(usage); // Set the Thread local as value has been modified
+ }
+ }
+ }
+
+ /**
+ * A POJO method has thrown an error.
+ * This method does nothing and wait for the finally.
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @param throwable : thrown error
+ * @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Member, java.lang.Throwable)
+ */
+ public void onError(Object pojo, Member method, Throwable throwable) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method has returned.
+ * @param pojo : POJO object.
+ * @param member : Method object.
+ * @param returnedObj : returned object (null for void method)
+ * @see org.apache.felix.ipojo.MethodInterceptor#onExit(java.lang.Object, java.lang.reflect.Member, java.lang.Object)
+ */
+ public void onExit(Object pojo, Member member, Object returnedObj) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method is finished.
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @see org.apache.felix.ipojo.MethodInterceptor#onFinally(java.lang.Object, java.lang.reflect.Member)
+ */
+ public void onFinally(Object pojo, Member method) {
+ if (m_usage != null) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ if (usage.dec()) {
+ // Exit the method flow => Release all objects
+ usage.clear();
+ m_usage.set(usage); // Set the Thread local as value has been modified
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates and returns object to inject in the dependency.
+ * This method handles aggregate, collection and proxy cases.
+ * @param refs the available service references
+ * @return the object to inject. Can be a 'simple' object, a proxy,
+ * a collection or an array.
+ */
+ private Object getServiceObjects(ServiceReference [] refs) {
+ if (m_proxy) {
+ if (m_proxyObject == null) { // Not aggregate.
+ return new ServiceCollection(this);
+ } else {
+ return m_proxyObject;
+ }
+ } else {
+ // Initialize the thread local object is not already touched.
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack == 0) { // uninitialized usage.
+ if (isAggregate()) {
+ if (m_collection) {
+ Collection svc = new ArrayList(refs.length); // Use an array list as collection implementation.
+ for (int i = 0; i < refs.length; i++) {
+ svc.add(getService(refs[i]));
+ }
+ usage.m_object = svc;
+ } else {
+ Object[] svc = (Object[]) Array.newInstance(getSpecification(),
+ refs.length);
+ for (int i = 0; i < svc.length; i++) {
+ svc[i] = getService(refs[i]);
+ }
+ usage.m_object = svc;
+ }
+ } else {
+ usage.m_object = getService(refs[0]);
+ }
+ usage.inc(); // Start the caching, so set the stack level to 1
+ m_usage.set(usage);
+ }
+ return usage.m_object;
+ }
+
+ }
+
+ /**
+ * Called by the proxy to get a service object to delegate a method.
+ * This methods manages the waited time and on timeout policies.
+ * @return a service object or a nullable/default-implmentation object.
+ */
+ public Object getService() {
+ ServiceReference ref = getServiceReference();
+ if (ref != null) {
+ return getService(ref); // Return immediately the service object.
+ } else {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+ synchronized (this) {
+ while (ref == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_timeout;
+ ref = getServiceReference();
+ }
+ }
+ }
+ // Check
+ if (exhausted) {
+ Object obj = onTimeout(); // Throw the Runtime Exception
+ if (obj == null) {
+ throw new RuntimeException("No service available"); // Runtime Exception to be consistent with iPOJO Core.
+ } else {
+ return obj; // Return a nullable or DI
+ }
+ } else {
+ // If not exhausted, ref is not null.
+ return getService(ref);
+ }
+ }
+ }
+
+ /**
+ * Start method. Initializes the nullable object.
+ * @see org.apache.felix.ipojo.util.DependencyModel#start()
+ */
+ public void start() {
+ super.start();
+ switch (m_policy) {
+ case TemporalHandler.NULL:
+ m_nullableObject = null;
+ break;
+ case TemporalHandler.NULLABLE:
+ // To load the proxy we use the POJO class loader. Indeed, this
+ // classloader imports iPOJO (so can access to Nullable) and has
+ // access to the service specification.
+ try {
+ m_nullableObject = Proxy.newProxyInstance(m_handler
+ .getInstanceManager().getClazz().getClassLoader(),
+ new Class[] { getSpecification(), Nullable.class },
+ new NullableObject()); // NOPMD
+ if (isAggregate()) {
+ if (m_collection) {
+ List list = new ArrayList(1);
+ list.add(m_nullableObject);
+ m_nullableObject = list;
+ } else {
+ Object[] array = (Object[]) Array.newInstance(
+ getSpecification(), 1);
+ array[0] = m_nullableObject;
+ m_nullableObject = array;
+ }
+ }
+ } catch (NoClassDefFoundError e) {
+ // A NoClassDefFoundError is thrown if the specification
+ // uses a
+ // class not accessible by the actual instance.
+ // It generally comes from a missing import.
+ throw new IllegalStateException(
+ "Cannot create the Nullable object, a referenced class cannot be loaded: "
+ + e.getMessage());
+ }
+
+ break;
+ case TemporalHandler.DEFAULT_IMPLEMENTATION:
+ // Create the default-implementation object.
+ try {
+ Class clazz = m_handler.getInstanceManager().getContext()
+ .getBundle().loadClass(m_di);
+ m_nullableObject = clazz.newInstance();
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(
+ "Cannot load the default-implementation " + m_di
+ + " : " + e.getMessage());
+ } catch (InstantiationException e) {
+ throw new IllegalStateException(
+ "Cannot load the default-implementation " + m_di
+ + " : " + e.getMessage());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(
+ "Cannot load the default-implementation " + m_di
+ + " : " + e.getMessage());
+ }
+ if (isAggregate()) {
+ if (m_collection) {
+ List list = new ArrayList(1);
+ list.add(m_nullableObject);
+ m_nullableObject = list;
+ } else {
+ Object[] array = (Object[]) Array.newInstance(
+ getSpecification(), 1);
+ array[0] = m_nullableObject;
+ m_nullableObject = array;
+ }
+ }
+ break;
+ case TemporalHandler.EMPTY:
+ if (! m_collection) {
+ m_nullableObject = Array.newInstance(getSpecification(), 0);
+ } else { // Empty collection
+ m_nullableObject = new ArrayList(0);
+ }
+ break;
+ default: // Cannot occurs
+ break;
+ }
+ }
+
+ /**
+ * Stop method. Just releases the reference on the nullable object.
+ * @see org.apache.felix.ipojo.util.DependencyModel#stop()
+ */
+ public void stop() {
+ super.stop();
+ m_nullableObject = null;
+ m_proxyObject = null;
+ }
+
+ /**
+ * The monitored field receives a value. Nothing to do.
+ * @param arg0 POJO setting the value.
+ * @param arg1 field name
+ * @param arg2 received value
+ * @see org.apache.felix.ipojo.FieldInterceptor#onSet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void onSet(Object arg0, String arg1, Object arg2) { }
+
+ /**
+ * Implements the timeout policy according to the specified configuration.
+ * @return the object to return when the timeout occurs.
+ */
+ Object onTimeout() {
+ switch (m_policy) {
+ case TemporalHandler.NULL:
+ case TemporalHandler.NULLABLE:
+ case TemporalHandler.DEFAULT_IMPLEMENTATION:
+ case TemporalHandler.EMPTY:
+ return m_nullableObject;
+ default:
+ // Throws a runtime exception
+ throw new RuntimeException("Service "
+ + getSpecification().getName()
+ + " unavailable : timeout");
+ }
+ }
+
+ long getTimeout() {
+ return m_timeout;
+ }
+
+ /**
+ * Creates proxy object for proxied scalar dependencies.
+ */
+ private class ProxyFactory extends ClassLoader {
+
+ /**
+ * Handler classloader, used to load the temporal dependency class.
+ */
+ private ClassLoader m_handlerCL;
+
+ /**
+ * Creates the proxy classloader.
+ * @param parent the handler classloader.
+ */
+ public ProxyFactory(ClassLoader parent) {
+ this.m_handlerCL = parent;
+ }
+
+ /**
+ * Loads a proxy class generated for the given (interface) class.
+ * @param clazz the service specification to proxy
+ * @return the Class object of the proxy.
+ */
+ protected Class getProxyClass(Class clazz) {
+ byte[] clz = ProxyGenerator.dumpProxy(clazz); // Generate the proxy.
+ return defineClass(clazz.getName() + "$$Proxy", clz, 0, clz.length);
+ }
+
+ /**
+ * Create a proxy object for the given specification. The proxy
+ * uses the given temporal dependency to get the service object.
+ * @param spec the service specification (interface)
+ * @param dep the temporal dependency used to get the service
+ * @return the proxy object.
+ */
+ public Object getProxy(Class spec, TemporalDependency dep) {
+ try {
+ Class clazz = getProxyClass(getSpecification());
+ Constructor constructor = clazz.getConstructor(new Class[] {dep.getClass()}); // The proxy constructor
+ return constructor.newInstance(new Object[] {dep});
+ } catch (Throwable e) {
+ m_handler.error("Cannot create the proxy object", e);
+ m_handler.getInstanceManager().stop();
+ return null;
+ }
+ }
+
+ /**
+ * Loads the given class.
+ * This class use the classloader of the specification class
+ * or the handler class loader.
+ * @param name the class name
+ * @return the class object
+ * @throws ClassNotFoundException if the class is not found by the two classloaders.
+ * @see java.lang.ClassLoader#loadClass(java.lang.String)
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+ try {
+ return m_handler.getInstanceManager().getContext().getBundle().loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return m_handlerCL.loadClass(name);
+ }
+ }
+ }
+
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
new file mode 100644
index 0000000..0056508
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
@@ -0,0 +1,317 @@
+/*
+ * 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.handler.temporal;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.DependencyMetadataHelper;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+import java.util.*;
+
+/**
+ * Temporal dependency handler.
+ * A temporal dependency waits (block) for the availability of the service.
+ * If no provider arrives in the specified among of time, a runtime exception is thrown.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TemporalHandler extends PrimitiveHandler implements DependencyStateListener {
+
+ /**
+ * Default timeout if not specified.
+ */
+ public static final int DEFAULT_TIMEOUT = 3000;
+ /**
+ * No policy.
+ */
+ public static final int NO_POLICY = 0;
+ /**
+ * Uses a nullable object.
+ */
+ public static final int NULLABLE = 1;
+ /**
+ * Uses a default-implementation object.
+ */
+ public static final int DEFAULT_IMPLEMENTATION = 2;
+ /**
+ * Uses an empty array.
+ */
+ public static final int EMPTY = 3;
+ /**
+ * Uses {@code null}.
+ */
+ public static final int NULL = 4;
+ /**
+ * The handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.handler.temporal";
+ /**
+ * The list of managed dependencies.
+ */
+ private List/*<deps>*/ m_dependencies = new ArrayList(1);
+
+ /**
+ * Start method. Starts managed dependencies.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ for (int i = 0; i < m_dependencies.size(); i++) {
+ ((TemporalDependency) m_dependencies.get(i)).start();
+ }
+ }
+
+ /**
+ * Stop method. Stops managed dependencies.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_dependencies.size(); i++) {
+ ((TemporalDependency) m_dependencies.get(i)).stop();
+ }
+ m_dependencies.clear();
+ }
+
+ /**
+ * Configure method. Creates managed dependencies.
+ *
+ * @param meta the component type metadata.
+ * @param dictionary the instance configuration.
+ * @throws ConfigurationException if the dependency is not configured correctly
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element meta, Dictionary dictionary) throws ConfigurationException {
+ PojoMetadata manipulation = getFactory().getPojoMetadata();
+ Element[] deps = meta.getElements("requires", NAMESPACE);
+
+ // Also check with temporal is no requires.
+ if (deps == null || deps.length == 0) {
+ deps = meta.getElements("temporal", NAMESPACE);
+ }
+
+ // Get instance filters.
+ Dictionary filtersConfiguration = getRequiresFilters(dictionary.get("temporal.filters"));
+ if (filtersConfiguration == null || filtersConfiguration.isEmpty()) {
+ // Fall back on the Requires handler configuration, if any
+ filtersConfiguration = getRequiresFilters(dictionary.get("requires.filters"));
+ }
+ // Get from filters if any.
+ Dictionary fromConfiguration = getRequiresFilters(dictionary.get("temporal.from"));
+ if (fromConfiguration == null || fromConfiguration.isEmpty()) {
+ // Fall back on the Requires handler configuration, if any
+ fromConfiguration = getRequiresFilters(dictionary.get("requires.from"));
+ }
+
+
+ for (int i = 0; i < deps.length; i++) {
+ if (!deps[i].containsAttribute("field") || m_dependencies.contains(deps[i].getAttribute("field"))) {
+ error("One temporal dependency must be attached to a field or the field is already used");
+ return;
+ }
+ String field = deps[i].getAttribute("field");
+
+ String id = field;
+ if (deps[i].containsAttribute("id")) {
+ id = deps[i].getAttribute("id");
+ }
+
+ FieldMetadata fieldmeta = manipulation.getField(field);
+ if (fieldmeta == null) {
+ error("The field " + field + " does not exist in the class " + getInstanceManager().getClassName());
+ return;
+ }
+
+ boolean agg = false;
+ boolean collection = false;
+ String spec = fieldmeta.getFieldType();
+ if (spec.endsWith("[]")) {
+ agg = true;
+ spec = spec.substring(0, spec.length() - 2);
+ } else if (Collection.class.getName().equals(spec)) {
+ agg = true;
+ collection = true;
+ // Collection detected. Check for the specification attribute
+ spec = deps[i].getAttribute("specification");
+ if (spec == null) {
+ error("A dependency injected inside a Collection must contain the 'specification' attribute");
+ }
+ }
+
+ // Determine the filter
+ String fil = deps[i].getAttribute("filter");
+ // Override the filter if filter configuration if available in the instance configuration
+ if (filtersConfiguration != null && id != null && filtersConfiguration.get(id) != null) {
+ fil = (String) filtersConfiguration.get(id);
+ }
+
+ // Check the from attribute
+ String from = deps[i].getAttribute("from");
+ if (fromConfiguration != null && id != null && fromConfiguration.get(id) != null) {
+ from = (String) fromConfiguration.get(id);
+ }
+
+ if (from != null) {
+ String fromFilter = "(|(instance.name=" + from + ")(service.pid=" + from + "))";
+ if (agg) {
+ warn("The 'from' attribute is incompatible with aggregate requirements: only one provider will " +
+ "match : " + fromFilter);
+ }
+ if (fil != null) {
+ fil = "(&" + fromFilter + fil + ")"; // Append the two filters
+ } else {
+ fil = fromFilter;
+ }
+ }
+
+ Filter filter = null;
+ if (fil != null) {
+ try {
+ filter = getInstanceManager().getContext().createFilter(fil);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("A requirement filter is invalid : " + filter, e);
+ }
+ }
+
+ String prox = deps[i].getAttribute("proxy");
+ // Use proxy by default except for array:
+ boolean proxy = prox == null || prox.equals("true");
+
+ if (prox == null && proxy) { // Proxy set because of the default.
+ if (agg && !collection) { // Aggregate and array
+ proxy = false;
+ }
+ }
+
+ if (proxy && agg) {
+ if (!collection) {
+ error("Proxied aggregate temporal dependencies cannot be an array. Only collections are supported");
+ }
+ }
+
+ long timeout = DEFAULT_TIMEOUT;
+ if (deps[i].containsAttribute("timeout")) {
+ String to = deps[i].getAttribute("timeout");
+ if (to.equalsIgnoreCase("infinite") || to.equalsIgnoreCase("-1")) {
+ timeout = Long.MAX_VALUE; // Infinite wait time ...
+ } else {
+ timeout = new Long(deps[i].getAttribute("timeout")).longValue();
+ }
+ }
+
+ int policy = NO_POLICY;
+ String di = null;
+ String onTimeout = deps[i].getAttribute("onTimeout");
+ if (onTimeout != null) {
+ if (onTimeout.equalsIgnoreCase("nullable")) {
+ policy = NULLABLE;
+ } else if (onTimeout.equalsIgnoreCase("empty-array") || onTimeout.equalsIgnoreCase("empty")) {
+ policy = EMPTY;
+ if (!agg) {
+ // The empty array policy can only be used on aggregate dependencies
+ error("Cannot use the empty array policy for " + field + " : non aggregate dependency.");
+ }
+ } else if (onTimeout.equalsIgnoreCase("null")) {
+ policy = NULL;
+ } else if (onTimeout.length() > 0) {
+ di = onTimeout;
+ policy = DEFAULT_IMPLEMENTATION;
+ }
+ }
+
+ Class specification = DependencyMetadataHelper.loadSpecification(spec, getInstanceManager().getContext());
+ TemporalDependency dep = new TemporalDependency(specification, agg, collection, proxy, filter, getInstanceManager().getContext(), timeout, policy, di, this);
+ m_dependencies.add(dep);
+
+ if (!proxy) { // Register method interceptor only if are not a proxy
+ MethodMetadata[] methods = manipulation.getMethods();
+ for (int k = 0; k < methods.length; k++) {
+ getInstanceManager().register(methods[k], dep);
+ }
+ }
+
+ getInstanceManager().register(fieldmeta, dep);
+ }
+ }
+
+ /**
+ * Gets the requires filter configuration from the given object.
+ * The given object must come from the instance configuration.
+ * This method was made to fix FELIX-2688. It supports filter configuration using
+ * an array:
+ * <code>{"myFirstDep", "(property1=value1)", "mySecondDep", "(property2=value2)"});</code>
+ * <p/>
+ * Copied from DependencyHandler#getRequiresFilters(Object)
+ *
+ * @param requiresFiltersValue the value contained in the instance
+ * configuration.
+ * @return the dictionary. If the object in already a dictionary, just returns it,
+ * if it's an array, builds the dictionary.
+ * @throws ConfigurationException the dictionary cannot be built
+ */
+ private Dictionary getRequiresFilters(Object requiresFiltersValue)
+ throws ConfigurationException {
+ if (requiresFiltersValue != null
+ && requiresFiltersValue.getClass().isArray()) {
+ String[] filtersArray = (String[]) requiresFiltersValue;
+ if (filtersArray.length % 2 != 0) {
+ throw new ConfigurationException(
+ "A requirement filter is invalid : "
+ + requiresFiltersValue);
+ }
+ Dictionary requiresFilters = new Hashtable();
+ for (int i = 0; i < filtersArray.length; i += 2) {
+ requiresFilters.put(filtersArray[i], filtersArray[i + 1]);
+ }
+ return requiresFilters;
+ }
+
+ return (Dictionary) requiresFiltersValue;
+ }
+
+ /**
+ * Nothing to do.
+ * A temporal dependency is always valid.
+ *
+ * @param dependencymodel dependency.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#invalidate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void invalidate(DependencyModel dependencymodel) {
+ }
+
+ /**
+ * Nothing to do.
+ * A temporal dependency is always valid.
+ *
+ * @param dependencymodel dependency.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#validate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void validate(DependencyModel dependencymodel) {
+ }
+
+
+}
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml b/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml
new file mode 100644
index 0000000..e514b20
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <handler
+ classname="org.apache.felix.ipojo.handler.temporal.TemporalHandler"
+ name="requires" namespace="org.apache.felix.ipojo.handler.temporal">
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.handler.temporal.TemporalHandler"
+ name="temporal" namespace="org.apache.felix.ipojo.handler.temporal">
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd b/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd
new file mode 100644
index 0000000..48dbc7f
--- /dev/null
+++ b/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd
@@ -0,0 +1,63 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handler.temporal"
+ xmlns="org.apache.felix.ipojo.handler.temporal"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="requires" type="TemporalServiceDependencyType"></xs:element>
+ <xs:element name="temporal" type="TemporalServiceDependencyType"></xs:element>
+
+
+ <xs:complexType name="TemporalServiceDependencyType">
+
+ <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="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The dependency id</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: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:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" use="optional" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>Enables or Disables the proxy injection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specification" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Specifies the looked service specification. This attribute is mandatory when injecting in a Collection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/pom.xml b/ipojo/handler/transaction/pom.xml
new file mode 100644
index 0000000..c526e43
--- /dev/null
+++ b/ipojo/handler/transaction/pom.xml
@@ -0,0 +1,115 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.transaction-handler-project</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Transaction Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>transaction-handler</module>
+ <module>transaction-handler-it</module>
+ </modules>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>DEPENDENCIES*</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>project</descriptorRef>
+ </descriptorRefs>
+ <!-- we don't want to attach all the assemblies, such as bz2 -->
+ <attach>false</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- only attach the project and bin assemblies, in tar.gz and zip flavors -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.tar.gz
+ </file>
+ <classifier>project</classifier>
+ <type>tar.gz</type>
+ </artifact>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.zip
+ </file>
+ <classifier>project</classifier>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/handler/transaction/transaction-handler-it/pom.xml b/ipojo/handler/transaction/transaction-handler-it/pom.xml
new file mode 100644
index 0000000..2d0364a
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/pom.xml
@@ -0,0 +1,413 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
+ <name>Apache Felix iPOJO Transaction Handler - Integration Test</name>
+ <artifactId>org.apache.felix.ipojo.handler.transaction-it</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.1</url.version>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>ow2.snapshots</id>
+ <url>http://repository.ow2.org/nexus/content/repositories/snapshots/</url>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.chameleon.transaction</groupId>
+ <artifactId>geronimo-transaction-service</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.transaction</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.6</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>regular</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/regular</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <!-- no test-all on transaction until we fix all issue on equinox and kf -->
+ <!--
+ <profile>
+ <id>test-all</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>equinox-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>equinox</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/equinox-native</cloneProjectsTo>
+
+ </configuration>
+ </execution>
+ <execution>
+ <id>felix-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/felix-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knopflerfish-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>knopflerfish</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/knopflerfish-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ -->
+
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+</project>
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/pom.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/pom.xml
new file mode 100644
index 0000000..f118348
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.transaction-it</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-transaction-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/ComponentUsingAnnotations.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/ComponentUsingAnnotations.java
new file mode 100644
index 0000000..432f833
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/ComponentUsingAnnotations.java
@@ -0,0 +1,53 @@
+/*
+ * 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.handler.transaction.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+import javax.transaction.Transaction;
+
+@Component
+@org.apache.felix.ipojo.transaction.Transaction(field="transaction")
+public class ComponentUsingAnnotations {
+
+ Transaction transaction;
+
+
+ @org.apache.felix.ipojo.transaction.Transactional
+ public void doSomethingBad() throws NullPointerException {
+ }
+
+ @org.apache.felix.ipojo.transaction.Transactional(propagation="required")
+ public void doSomethingBad2() throws UnsupportedOperationException {
+
+ }
+
+ @org.apache.felix.ipojo.transaction.Transactional(propagation="supported", norollbackfor= {"java.lang.Exception"})
+ public void doSomethingGood() {
+
+ }
+
+ @org.apache.felix.ipojo.transaction.Transactional(timeout=1000, exceptiononrollback=true)
+ public void doSomethingLong() {
+
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooDelegator.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooDelegator.java
new file mode 100644
index 0000000..b32ae26
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooDelegator.java
@@ -0,0 +1,96 @@
+/*
+ * 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.handler.transaction.components;
+
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+
+import javax.transaction.Transaction;
+
+public class FooDelegator implements CheckService {
+
+ Transaction transaction;
+ Transaction lastCommitted;
+ Transaction lastRolledback;
+ Transaction current;
+ private Foo foo;
+ private int commit;
+ private int rollback;
+
+ public void onCommit(String method) {
+ commit++;
+ }
+
+ public void onRollback(String method, Exception e) {
+ rollback++;
+ }
+
+ public void doSomethingBad() throws NullPointerException {
+ current = transaction;
+ foo.doSomethingBad();
+ }
+
+ public void doSomethingBad2() throws UnsupportedOperationException {
+ current = transaction;
+ foo.doSomethingBad2();
+
+ }
+
+ public void doSomethingGood() {
+ current = transaction;
+ foo.doSomethingGood();
+ }
+
+ public void doSomethingLong() {
+ current = transaction;
+ foo.doSomethingLong();
+ }
+
+ public Transaction getCurrentTransaction() {
+ return current;
+ }
+
+ public int getNumberOfCommit() {
+ return commit;
+ }
+
+ public int getNumberOfRollback() {
+ return rollback;
+ }
+
+ public Transaction getLastRolledBack() {
+ return lastRolledback;
+ }
+
+ public Transaction getLastCommitted() {
+ return lastCommitted;
+ }
+
+ public void onRollback(Transaction t) {
+ lastRolledback = t;
+ rollback++;
+ }
+
+ public void onCommit(Transaction t) {
+ lastCommitted = t;
+ commit++;
+ }
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooImpl.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooImpl.java
new file mode 100644
index 0000000..8ac8146
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/components/FooImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.handler.transaction.components;
+
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+
+public class FooImpl implements Foo {
+
+ public void doSomethingBad() throws NullPointerException {
+ throw new NullPointerException("NULL");
+ }
+
+ public void doSomethingBad2() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Expected exception");
+
+ }
+
+ public void doSomethingGood() {
+ // Good...
+ }
+
+ public void doSomethingLong() {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/CheckService.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/CheckService.java
new file mode 100644
index 0000000..f2c978f
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/CheckService.java
@@ -0,0 +1,44 @@
+/*
+ * 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.handler.transaction.services;
+
+import javax.transaction.Transaction;
+
+public interface CheckService {
+
+ public void doSomethingGood();
+
+ public void doSomethingBad() throws NullPointerException;
+
+ public void doSomethingBad2() throws UnsupportedOperationException;
+
+ public void doSomethingLong();
+
+ public int getNumberOfCommit();
+
+ public int getNumberOfRollback();
+
+ public Transaction getCurrentTransaction();
+
+ public Transaction getLastRolledBack();
+
+ public Transaction getLastCommitted();
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/Foo.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/Foo.java
new file mode 100644
index 0000000..9107979
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/java/org/apache/felix/ipojo/handler/transaction/services/Foo.java
@@ -0,0 +1,32 @@
+/*
+ * 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.handler.transaction.services;
+
+public interface Foo {
+
+ public void doSomethingGood();
+
+ public void doSomethingBad() throws NullPointerException;
+
+ public void doSomethingBad2() throws UnsupportedOperationException;
+
+ public void doSomethingLong();
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/annotation.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/annotation.xml
new file mode 100644
index 0000000..97fa837
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/annotation.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/foo.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/foo.xml
new file mode 100644
index 0000000..2bc6421
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/foo.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooImpl">
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/mandatory.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/mandatory.xml
new file mode 100644
index 0000000..b9c74a1
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/mandatory.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="mandatory-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood" propagation="mandatory"/>
+ <transactional method="getCurrentTransaction" propagation="mandatory"/>
+ <transactional method="doSomethingBad" propagation="mandatory"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="mandatory"/>
+ <transactional method="doSomethingLong" propagation="mandatory"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="mandatory-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood" propagation="mandatory"/>
+ <transactional method="getCurrentTransaction" propagation="mandatory"/>
+ <transactional method="doSomethingBad" propagation="mandatory"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="mandatory"/>
+ <transactional method="doSomethingLong" propagation="mandatory"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/never.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/never.xml
new file mode 100644
index 0000000..bad5164
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/never.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="never-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood" propagation="never"/>
+ <transactional method="getCurrentTransaction" propagation="never"/>
+ <transactional method="doSomethingBad" propagation="never"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="never"/>
+ <transactional method="doSomethingLong" propagation="never"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="never-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood" propagation="never"/>
+ <transactional method="getCurrentTransaction" propagation="never"/>
+ <transactional method="doSomethingBad" propagation="never"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="never"/>
+ <transactional method="doSomethingLong" propagation="never"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/notsupported.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/notsupported.xml
new file mode 100644
index 0000000..8808854
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/notsupported.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="notsupported-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood" propagation="notsupported"/>
+ <transactional method="getCurrentTransaction" propagation="notsupported"/>
+ <transactional method="doSomethingBad" propagation="notsupported"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="notsupported"/>
+ <transactional method="doSomethingLong" propagation="notsupported"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="notsupported-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood" propagation="notsupported"/>
+ <transactional method="getCurrentTransaction" propagation="notsupported"/>
+ <transactional method="doSomethingBad" propagation="notsupported"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="notsupported"/>
+ <transactional method="doSomethingLong" propagation="notsupported"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requires.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requires.xml
new file mode 100644
index 0000000..f209c65
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requires.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="requires-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood"/>
+ <transactional method="getCurrentTransaction"/>
+ <transactional method="doSomethingBad"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException"/>
+ <transactional method="doSomethingLong"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="requires-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood"/>
+ <transactional method="getCurrentTransaction"/>
+ <transactional method="doSomethingBad"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException"/>
+ <transactional method="doSomethingLong"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requiresnew.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requiresnew.xml
new file mode 100644
index 0000000..0fcc9e9
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/requiresnew.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="requiresnew-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood" propagation="requiresnew"/>
+ <transactional method="getCurrentTransaction" propagation="requiresnew"/>
+ <transactional method="doSomethingBad" propagation="requiresnew" exceptiononrollback="true"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="requiresnew"/>
+ <transactional method="doSomethingLong" propagation="requiresnew"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="requiresnew-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood" propagation="requiresnew"/>
+ <transactional method="getCurrentTransaction" propagation="requiresnew"/>
+ <transactional method="doSomethingBad" propagation="requiresnew"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="requiresnew"/>
+ <transactional method="doSomethingLong" propagation="requiresnew"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/supported.xml b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/supported.xml
new file mode 100644
index 0000000..7a56e5f
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/main/resources/supported.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:tr="org.apache.felix.ipojo.transaction">
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="supported-ok">
+ <provides/>
+ <requires field="foo"/>
+ <tr:transaction field="transaction">
+ <transactional method="doSomethingGood" propagation="supported"/>
+ <transactional method="getCurrentTransaction" propagation="supported"/>
+ <transactional method="doSomethingBad" propagation="supported"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="supported"/>
+ <transactional method="doSomethingLong" propagation="supported"/>
+ </tr:transaction>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.transaction.components.FooDelegator" name="supported-cb">
+ <provides/>
+ <requires field="foo" />
+ <tr:transaction field="transaction" onCommit="onCommit" onRollback="onRollback">
+ <transactional method="doSomethingGood" propagation="supported"/>
+ <transactional method="getCurrentTransaction" propagation="supported"/>
+ <transactional method="doSomethingBad" propagation="supported"/>
+ <transactional method="doSomethingBad2" norollbackfor="java.lang.UnsupportedOperationException" propagation="supported"/>
+ <transactional method="doSomethingLong" propagation="supported"/>
+ </tr:transaction>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/Common.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/Common.java
new file mode 100644
index 0000000..87aa4c1
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/Common.java
@@ -0,0 +1,217 @@
+/*
+ * 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.handler.transaction.test;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+
+/**
+ * Bootstrap the test from this project
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerMethod.class)
+public class Common {
+
+ @Inject
+ BundleContext context;
+ OSGiHelper osgiHelper;
+ IPOJOHelper ipojoHelper;
+
+ public static Option junitAndMockitoBundles() {
+ return new DefaultCompositeOption(
+ // Repository required to load harmcrest (OSGi-fied version).
+ repository("http://repository.springsource.com/maven/bundles/external").id(
+ "com.springsource.repository.bundles.external"),
+
+ // Hamcrest with a version matching the range expected by Mockito
+ mavenBundle("org.hamcrest", "com.springsource.org.hamcrest.core", "1.1.0"),
+
+ // Mockito core does not includes Hamcrest
+ mavenBundle("org.mockito", "mockito-core", "1.9.5"),
+
+ // Objenesis with a version matching the range expected by Mockito
+ wrappedBundle(mavenBundle("org.objenesis", "objenesis", "1.2"))
+ .exports("*;version=1.2"),
+
+ // The default JUnit bundle also exports Hamcrest, but with an (incorrect) version of
+ // 4.9 which does not match the Mockito import. When deployed after the hamcrest bundles, it gets
+ // resolved correctly.
+ CoreOptions.junitBundles(),
+
+ /*
+ * Felix has implicit boot delegation enabled by default. It conflicts with Mockito:
+ * java.lang.LinkageError: loader constraint violation in interface itable initialization:
+ * when resolving method "org.osgi.service.useradmin.User$$EnhancerByMockitoWithCGLIB$$dd2f81dc
+ * .newInstance(Lorg/mockito/cglib/proxy/Callback;)Ljava/lang/Object;" the class loader
+ * (instance of org/mockito/internal/creation/jmock/SearchingClassLoader) of the current class,
+ * org/osgi/service/useradmin/User$$EnhancerByMockitoWithCGLIB$$dd2f81dc, and the class loader
+ * (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) for interface
+ * org/mockito/cglib/proxy/Factory have different Class objects for the type org/mockito/cglib/
+ * proxy/Callback used in the signature
+ *
+ * So we disable the bootdelegation. this property has no effect on the other OSGi implementation.
+ */
+ frameworkProperty("felix.bootdelegation.implicit").value("false")
+ );
+ }
+
+ public static CompositeOption ipojoBundles() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo").versionAsInProject(),
+ mavenBundle("org.ow2.chameleon.testing", "osgi-helpers").versionAsInProject(),
+ // The tested handler
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.transaction").versionAsInProject()
+ );
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(Level.DEBUG);
+
+ return options(
+ cleanCaches(),
+ ipojoBundles(),
+ junitBundles(),
+ //testedBundle(), // Each test is doing its own deployment.
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
+ provision(
+ mavenBundle().groupId("org.ow2.chameleon.transaction").artifactId("geronimo-transaction-service").version(asInProject())
+ ),
+ systemPackage("javax.transaction;version>=1.1.0")
+ );
+ }
+
+ @Before
+ public void commonSetUp() {
+ osgiHelper = new OSGiHelper(context);
+ ipojoHelper = new IPOJOHelper(context);
+
+ // Dump OSGi Framework information
+ String vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VENDOR);
+ if (vendor == null) {
+ vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_SYMBOLICNAME);
+ }
+ String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
+ System.out.println("OSGi Framework : " + vendor + " - " + version);
+ }
+
+ @After
+ public void commonTearDown() {
+ ipojoHelper.dispose();
+ osgiHelper.dispose();
+ }
+
+ public Option testedBundle() throws MalformedURLException {
+ File out = new File("target/tested/bundle.jar");
+
+ TinyBundle tested = TinyBundles.bundle();
+
+ // We look inside target/classes to find the class and resources
+ File classes = new File("target/classes");
+ Collection<File> files = FileUtils.listFilesAndDirs(classes, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
+ List<File> services = new ArrayList<File>();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // By convention we export of .services and .service package
+ if (file.getName().endsWith("services") || file.getName().endsWith("service")) {
+ services.add(file);
+ }
+ } else {
+ // We need to compute the path
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() + 1);
+ tested.add(path, file.toURI().toURL());
+ System.out.println(file.getName() + " added to " + path);
+ }
+ }
+
+ String export = "";
+ for (File file : services) {
+ if (export.length() > 0) {
+ export += ", ";
+ }
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() + 1);
+ String packageName = path.replace('/', '.');
+ export += packageName;
+ }
+
+ System.out.println("Exported packages : " + export);
+
+ InputStream inputStream = tested
+ .set(Constants.BUNDLE_SYMBOLICNAME, "test.bundle")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ //.set(Constants.EXPORT_PACKAGE, export) // No export...
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources")));
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the manipulated bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the manipulated bundle");
+ }
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestAnnotations.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestAnnotations.java
new file mode 100644
index 0000000..2e96e29
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestAnnotations.java
@@ -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.felix.ipojo.handler.transaction.test;
+
+import org.apache.felix.ipojo.handler.transaction.components.ComponentUsingAnnotations;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestAnnotations extends Common {
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(TinyBundles.withBnd());
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(ComponentUsingAnnotations.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "TransactionAnnotationTest")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "annotation.xml")));
+
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ),
+ repository("http://maven.ow2.org/maven2-snapshot/")
+ );
+ }
+
+ @Test
+ public void annotations() {
+ Element elem = IPOJOHelper.getMetadata(getBundle(), "org.apache.felix.ipojo.handler.transaction.components.ComponentUsingAnnotations");
+ Assert.assertNotNull(elem);
+
+ Element tr = elem.getElements("transaction", "org.apache.felix.ipojo.transaction")[0];
+ Assert.assertEquals("transaction", tr.getAttribute("field"));
+
+ Assert.assertNull(tr.getAttribute("oncommit"));
+ Assert.assertNull(tr.getAttribute("onrollback"));
+
+ Element[] methods = tr.getElements();
+ Assert.assertEquals(4, methods.length);
+
+ Element m1 = getElementByMethod(methods, "doSomethingBad");
+ Assert.assertNotNull(m1);
+
+ Element m2 = getElementByMethod(methods, "doSomethingBad2");
+ Assert.assertNotNull(m2);
+ Assert.assertEquals("required", m2.getAttribute("propagation"));
+
+ Element m3 = getElementByMethod(methods, "doSomethingGood");
+ Assert.assertNotNull(m3);
+ Assert.assertEquals("supported", m3.getAttribute("propagation"));
+ Assert.assertEquals("{java.lang.Exception}", m3.getAttribute("norollbackfor"));
+
+ Element m4 = getElementByMethod(methods, "doSomethingLong");
+ Assert.assertNotNull(m4);
+ Assert.assertEquals("1000", m4.getAttribute("timeout"));
+ Assert.assertEquals("true", m4.getAttribute("exceptiononrollback"));
+ }
+
+ private Element getElementByMethod(Element[] e, String m) {
+ for (Element elem : e) {
+ if (m.equals(elem.getAttribute("method"))) {
+ return elem;
+ }
+ }
+ Assert.fail("Method " + m + " not found");
+ return null;
+ }
+
+ private Bundle getBundle() {
+ for (Bundle b : context.getBundles()) {
+ System.out.println(b.getSymbolicName());
+ if ("TransactionAnnotationTest".equals(b.getSymbolicName())) {
+ return b;
+ }
+ }
+ Assert.fail("Cannot find the tested bundle");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInstallation.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInstallation.java
new file mode 100644
index 0000000..8f68dc3
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInstallation.java
@@ -0,0 +1,128 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestInstallation extends Common {
+
+ public static final File TEST = new File("src/main/resources");
+
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "RequiredTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "requires.xml")));
+
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+ }
+
+ @Test
+ public void install() throws NotSupportedException, SystemException, IllegalStateException,
+ SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException, InvalidSyntaxException {
+ Bundle[] bundles = context.getBundles();
+ for (Bundle b : bundles) {
+ System.out.println("Bundle : " + b.getSymbolicName() + " - " + b.getState());
+ Assert.assertTrue(b.getSymbolicName(), b.getState() == Bundle.ACTIVE);
+ }
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ // Transaction Service available
+ osgiHelper.isServiceAvailable(TransactionManager.class.getName());
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Assert.assertNotNull(tm.getTransaction());
+ tm.commit();
+
+ tm.begin();
+ Assert.assertNotNull(tm.getTransaction());
+ tm.rollback();
+
+ // Handler exposed
+ ServiceReference ref = osgiHelper.getServiceReference(HandlerFactory.class.getName(), "(&(handler.name=transaction)(handler.namespace=org.apache.felix.ipojo.transaction))");
+ Assert.assertNotNull(ref);
+
+ // Create an install of the components
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference[] refs = context.getAllServiceReferences(CheckService.class.getName(), "(instance.name=" + under.getInstanceName() + ")");
+
+// ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(refs);
+
+ ((CheckService) osgiHelper.getServiceObject(refs[0])).doSomethingGood();
+ }
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInvalidation.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInvalidation.java
new file mode 100644
index 0000000..caf1e59
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestInvalidation.java
@@ -0,0 +1,121 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestInvalidation extends Common {
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "RequiredTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "requires.xml")));
+
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+ }
+
+ @Test
+ public void testInvalidation() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ final ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+
+ Thread thread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ prov.dispose();
+ }
+ });
+
+ thread.start();
+
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingLong(); // 5s, so prov should be disposed during this time and under becomes invalid
+
+ Assert.assertEquals(ComponentInstance.INVALID, under.getState());
+
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.rollback();
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestMandatory.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestMandatory.java
new file mode 100644
index 0000000..8edec83
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestMandatory.java
@@ -0,0 +1,397 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+
+public class TestMandatory extends Common {
+
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MandatoryTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "mandatory.xml")));
+
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingGood(); // Fail !
+ }
+
+ @Test
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad(); // Fail, RTE thrown before the other exception
+ }
+
+ @Test(expected = RollbackException.class)
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.commit(); // Throws a rollback exception.
+ }
+
+ @Test
+ public void testExceptionInsideTransactionRB() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.rollback();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2(); // Throws a RTE
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testOkOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingGood(); // Throws a RTE.
+
+ }
+
+ @Test
+ public void testOkInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad(); // Thows a RTE.
+
+ }
+
+ @Test
+ public void testExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ try {
+ t.commit(); // Throw a rollback exception.
+ } catch (RollbackException e) {
+ // Expected
+ } catch (Throwable e) {
+ Assert.fail(e.getMessage()); // Unexpected
+ }
+
+ Assert.assertNotNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(1, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastRolledBack());
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testExpectedExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad2();
+
+
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("mandatory-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNever.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNever.java
new file mode 100644
index 0000000..d8c6b59
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNever.java
@@ -0,0 +1,169 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestNever extends Common {
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "NeverTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "never.xml")));
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+ }
+
+ @Test
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("never-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingGood();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("never-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ cs.doSomethingGood(); // Fail
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("never-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad(); // Throws an NPE
+ }
+
+ @Test
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("never-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad(); // Fail
+ Assert.fail("RuntimeException expected");
+ } catch (RuntimeException e) {
+ // Ok :-)
+ }
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.rollback();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("never-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2();
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNotSupported.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNotSupported.java
new file mode 100644
index 0000000..b9fdd96
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestNotSupported.java
@@ -0,0 +1,403 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+@ExamReactorStrategy(PerClass.class)
+public class TestNotSupported extends Common {
+
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "NotSupportedTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "notsupported.xml")));
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+ }
+
+ @Test
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = ((CheckService) osgiHelper.getServiceObject(ref));
+ cs.doSomethingGood();
+ // No transaction.
+ }
+
+ @Test
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction(); // Is executed in the transaction despite it's not supported.
+ Assert.assertSame(t2, t);
+ t.commit();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad();
+ }
+
+ @Test
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus()); // No impact on the transaction.
+
+ t.commit(); // Ok.
+ }
+
+ @Test
+ public void testExceptionInsideTransactionRB() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus()); // No impact on the transaction.
+
+ t.rollback(); // Ok.
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2();
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+
+ @Test
+ public void testOkOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingGood();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testOkInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus()); // No effect on the transaction
+
+ try {
+ t.commit(); // Throw a rollback exception.
+ } catch (RollbackException e) {
+ // Expected
+ } catch (Throwable e) {
+ Assert.fail(e.getMessage()); // Unexpected
+ }
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad2();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("notsupported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequires.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequires.java
new file mode 100644
index 0000000..6221293
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequires.java
@@ -0,0 +1,406 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestRequires extends Common {
+
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "RequiresTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "requires.xml")));
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+
+ }
+
+ @Test
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingGood();
+ }
+
+ @Test
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad();
+ }
+
+ @Test(expected = RollbackException.class)
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.commit(); // Throw a rollback exception.
+ }
+
+ @Test
+ public void testExceptionInsideTransactionRB() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.rollback();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2();
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+
+ @Test
+ public void testOkOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingGood();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testOkInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad();
+
+ Assert.assertNotNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(1, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ try {
+ t.commit(); // Throw a rollback exception.
+ } catch (RollbackException e) {
+ // Expected
+ } catch (Throwable e) {
+ Assert.fail(e.getMessage()); // Unexpected
+ }
+
+ Assert.assertNotNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(1, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastRolledBack());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad2();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requires-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequiresNew.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequiresNew.java
new file mode 100644
index 0000000..b18733f
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestRequiresNew.java
@@ -0,0 +1,219 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+public class TestRequiresNew extends Common {
+
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "RequiresNewTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "requiresnew.xml")));
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ )
+ );
+
+
+ }
+
+ @Test
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingGood(); // Ok
+ }
+
+ @Test
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertNotSame(t2, t); // Two different transactions
+ // Check that t2 is commited => no transaction
+ Assert.assertEquals(Status.STATUS_NO_TRANSACTION, t2.getStatus());
+ t.commit();
+ }
+
+ @Test
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ try {
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad(); // throws an exception on rollback
+ Assert.fail("Exception expected on rollback");
+ } catch (IllegalStateException e) {
+ // Ok.
+ } catch (Exception e) {
+ Assert.fail("IllegalStateException expected on rollback");
+ }
+ }
+
+ @Test
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("IllegalStateException expected"); // throws an exception on rollback
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof IllegalStateException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertNotSame(t2, t);
+ // Check that t2 is rolledback
+ Assert.assertEquals(Status.STATUS_NO_TRANSACTION, t2.getStatus());
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2();
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("requiresnew-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertNotSame(t2, t);
+ Assert.assertEquals(Status.STATUS_NO_TRANSACTION, t2.getStatus());
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestSupported.java b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestSupported.java
new file mode 100644
index 0000000..f36c4e6
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/it/transaction-it/src/test/java/org/apache/felix/ipojo/handler/transaction/test/TestSupported.java
@@ -0,0 +1,411 @@
+/*
+ * 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.handler.transaction.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handler.transaction.components.FooDelegator;
+import org.apache.felix.ipojo.handler.transaction.components.FooImpl;
+import org.apache.felix.ipojo.handler.transaction.services.CheckService;
+import org.apache.felix.ipojo.handler.transaction.services.Foo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.transaction.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy.withiPOJO;
+
+@ExamReactorStrategy(PerClass.class)
+public class TestSupported extends Common {
+
+
+ public static final File TEST = new File("src/main/resources");
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+
+ InputStream service = TinyBundles.bundle()
+ .add(CheckService.class)
+ .add(Foo.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Service")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build();
+
+ InputStream fooimpl = TinyBundles.bundle()
+ .add(FooImpl.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Foo Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services")
+ .build(withiPOJO(new File(TEST, "foo.xml")));
+
+ InputStream test = TinyBundles.bundle()
+ .add(FooDelegator.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "SupportedTransactionPropagation")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.handler.transaction.services, javax.transaction;version=1.1")
+ .build(withiPOJO(new File(TEST, "supported.xml")));
+
+ return OptionUtils.combine(
+ options,
+ provision(
+ service,
+ fooimpl,
+ test
+ ));
+ }
+
+ @Test
+ public void testOkOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = ((CheckService) osgiHelper.getServiceObject(ref));
+ cs.doSomethingGood();
+ // No transaction.
+ }
+
+ @Test
+ public void testOkInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad();
+ }
+
+ @Test(expected = RollbackException.class)
+ public void testExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.commit(); // Throw a rollback exception.
+ }
+
+ @Test
+ public void testExceptionInsideTransactionRB() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ t.rollback();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransaction() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ ((CheckService) osgiHelper.getServiceObject(ref)).doSomethingBad2();
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransaction() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-ok");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+ }
+
+ @Test
+ public void testOkOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingGood();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testOkInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ cs.doSomethingGood();
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad();
+ Assert.fail("NullPointerException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof NullPointerException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_MARKED_ROLLBACK, t.getStatus());
+
+ try {
+ t.commit(); // Throw a rollback exception.
+ } catch (RollbackException e) {
+ // Expected
+ } catch (Throwable e) {
+ Assert.fail(e.getMessage()); // Unexpected
+ }
+
+ Assert.assertNotNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(1, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastRolledBack());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testExpectedExceptionOutsideTransactionWithCallback() {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+
+ cs.doSomethingBad2();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNull(cs.getLastCommitted());
+ Assert.assertEquals(0, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+ }
+
+ @Test
+ public void testExpectedExceptionInsideTransactionWithCallback() throws NotSupportedException, SystemException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException {
+ ComponentInstance prov = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.handler.transaction.components.FooImpl");
+ ComponentInstance under = ipojoHelper.createComponentInstance("supported-cb");
+
+ Assert.assertEquals(ComponentInstance.VALID, prov.getState());
+ Assert.assertEquals(ComponentInstance.VALID, under.getState());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), under.getInstanceName());
+ Assert.assertNotNull(ref);
+
+ osgiHelper.waitForService(TransactionManager.class.getName(), null, 5000);
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ TransactionManager tm = (TransactionManager) osgiHelper.getServiceObject(TransactionManager.class.getName(), null);
+ tm.begin();
+ Transaction t = tm.getTransaction();
+ try {
+ cs.doSomethingBad2();
+ Assert.fail("UnsupportedOperationException expected");
+ } catch (Exception e) {
+ Assert.assertTrue(e instanceof UnsupportedOperationException);
+ }
+ Transaction t2 = cs.getCurrentTransaction();
+ Assert.assertSame(t2, t);
+ Assert.assertEquals(Status.STATUS_ACTIVE, t.getStatus());
+
+ t.commit();
+
+ Assert.assertNull(cs.getLastRolledBack());
+ Assert.assertNotNull(cs.getLastCommitted());
+ Assert.assertEquals(1, cs.getNumberOfCommit());
+ Assert.assertEquals(0, cs.getNumberOfRollback());
+
+ Assert.assertSame(t, cs.getLastCommitted());
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/transaction/transaction-handler-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/transaction/transaction-handler/pom.xml b/ipojo/handler/transaction/transaction-handler/pom.xml
new file mode 100644
index 0000000..9c09988
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/pom.xml
@@ -0,0 +1,99 @@
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <artifactId>org.apache.felix.ipojo.handler.transaction
+ </artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Transaction Handler</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>1.4.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package>org.apache.felix.ipojo.transaction</Private-Package>
+ <Import-Package>javax.transaction;version=1.1, *</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.4</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>
+ http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml
+ </configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>geronimo-spec</groupId>
+ <artifactId>geronimo-spec-jta</artifactId>
+ <version>1.0-M1</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionHandler.java b/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionHandler.java
new file mode 100644
index 0000000..d0eea3f
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionHandler.java
@@ -0,0 +1,310 @@
+/*
+ * 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.transaction;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.util.Callback;
+
+public class TransactionHandler extends PrimitiveHandler implements Synchronization {
+
+ public static final String NAMESPACE= "org.apache.felix.ipojo.transaction";
+
+ public static final String NAME= "transaction";
+
+ private static final String FIELD_ATTRIBUTE= "field";
+
+ private static final String ONCOMMIT_ATTRIBUTE= "oncommit";
+
+ private static final String ONROLLBACK_ATTRIBUTE= "onrollback";
+
+ private static final String TRANSACTIONAL_ELEMENT = "transactional";
+
+ private static final String METHOD_ATTRIBUTE = "method";
+
+ private static final String TIMEOUT_ATTRIBUTE = "timeout";
+
+ private static final String PROPAGATION_ATTRIBUTE = "propagation";
+
+ private static final String EXCEPTIONONROLLBACK_ATTRIBUTE = "exceptiononrollback";
+
+ private static final String NOROLLBACKFOR_ATTRIBUTE = "norollbackfor";
+
+ public static final int DEFAULT_PROPAGATION = TransactionalMethod.REQUIRES;
+
+
+ private TransactionManager m_transactionManager; // Service Dependency
+
+ private List<TransactionalMethod> m_methods = new ArrayList<TransactionalMethod>();
+
+ private Callback m_onRollback;
+
+ private Callback m_onCommit;
+
+ private List<Transaction> m_transactions = new ArrayList<Transaction>();
+
+
+ public void configure(Element arg0, Dictionary arg1)
+ throws ConfigurationException {
+ Element[] elements = arg0.getElements(NAME, NAMESPACE);
+ if (elements.length > 1) {
+ throw new ConfigurationException("The handler " + NAMESPACE + ":" + NAME + " cannot be declared several times");
+ }
+
+ String field = elements[0].getAttribute(FIELD_ATTRIBUTE);
+ if (field != null) {
+ FieldMetadata meta = getPojoMetadata().getField(field);
+ if (meta == null) {
+ throw new ConfigurationException("The transaction field does not exist in the pojo class : " + field);
+ }
+ if (! meta.getFieldType().equals(Transaction.class.getName())) {
+ throw new ConfigurationException("The transaction field type must be " + Transaction.class.getName());
+ }
+ // Register the interceptor
+ getInstanceManager().register(meta, this);
+
+ }
+
+ String oncommit = elements[0].getAttribute(ONCOMMIT_ATTRIBUTE);
+ if (oncommit != null) {
+ m_onCommit = new Callback(oncommit, new String[] { Transaction.class.getName() }, false, getInstanceManager());
+ }
+
+ String onrollback = elements[0].getAttribute(ONROLLBACK_ATTRIBUTE);
+ if (onrollback != null) {
+ m_onRollback = new Callback(onrollback, new String[] { Transaction.class.getName() }, false, getInstanceManager());
+ }
+
+
+ Element[] sub = elements[0].getElements(TRANSACTIONAL_ELEMENT);
+ if (sub == null || sub.length == 0) {
+ throw new ConfigurationException("The handler " + NAMESPACE + ":" + NAME + " must have " + TRANSACTIONAL_ELEMENT + " subelement");
+ }
+
+ for (int i = 0; i < sub.length; i++) {
+ String method = sub[i].getAttribute(METHOD_ATTRIBUTE);
+ String to = sub[i].getAttribute(TIMEOUT_ATTRIBUTE);
+ String propa = sub[i].getAttribute(PROPAGATION_ATTRIBUTE);
+ String nrbf = sub[i].getAttribute(NOROLLBACKFOR_ATTRIBUTE);
+ String eorb = sub[i].getAttribute(EXCEPTIONONROLLBACK_ATTRIBUTE);
+
+ if (method == null) {
+ throw new ConfigurationException("A transactional element must specified the method attribute");
+ }
+ MethodMetadata meta = this.getPojoMetadata().getMethod(method);
+ if (meta == null) {
+ throw new ConfigurationException("A transactional method is not in the pojo class : " + method);
+ }
+
+ int timeout = 0;
+ if (to != null) {
+ timeout = new Integer(to).intValue();
+ }
+
+ int propagation = DEFAULT_PROPAGATION;
+ if (propa != null) {
+ propagation = parsePropagation(propa);
+ }
+
+ List<String> exceptions = new ArrayList<String>();
+ if (nrbf != null) {
+ exceptions = (List<String>) ParseUtils.parseArraysAsList(nrbf);
+ }
+
+ boolean exceptionOnRollback = false;
+ if (eorb != null) {
+ exceptionOnRollback = new Boolean(eorb).booleanValue();
+ }
+
+ TransactionalMethod tm = new TransactionalMethod(method, propagation, timeout, exceptions, exceptionOnRollback, this);
+ m_methods.add(tm);
+ this.getInstanceManager().register(meta, tm);
+ }
+
+ }
+
+ private int parsePropagation(String propa) throws ConfigurationException {
+ if (propa.equalsIgnoreCase("requires")) {
+ return TransactionalMethod.REQUIRES;
+
+ } else if (propa.equalsIgnoreCase("mandatory")){
+ return TransactionalMethod.MANDATORY;
+
+ } else if (propa.equalsIgnoreCase("notsupported")) {
+ return TransactionalMethod.NOT_SUPPORTED;
+
+ } else if (propa.equalsIgnoreCase("supported")) {
+ return TransactionalMethod.SUPPORTED;
+
+ } else if (propa.equalsIgnoreCase("never")) {
+ return TransactionalMethod.NEVER;
+
+ } else if (propa.equalsIgnoreCase("requiresnew")) {
+ return TransactionalMethod.REQUIRES_NEW;
+ }
+
+ throw new ConfigurationException("Unknown propgation policy : " + propa);
+ }
+
+ public void start() {
+ // Set transaction managers.
+ for (TransactionalMethod method : m_methods) {
+ method.setTransactionManager(m_transactionManager);
+ }
+ }
+
+ public void stop() {
+ // Nothing to do.
+ }
+
+ public synchronized void bind(TransactionManager tm) {
+ for (TransactionalMethod method : m_methods) {
+ method.setTransactionManager(tm);
+ }
+ }
+
+ public synchronized void unbind(TransactionManager tm) {
+ for (TransactionalMethod method : m_methods) {
+ method.setTransactionManager(null);
+ }
+ }
+
+ public void transactionRolledback(Transaction t) {
+ if (m_onRollback != null) {
+ try {
+ m_onRollback.call(new Object[] { t });
+ } catch (NoSuchMethodException e1) {
+ error("Cannot invoke the onRollback method, method not found",
+ e1);
+ } catch (IllegalAccessException e1) {
+ error(
+ "Cannot invoke the onRollback method,cannot access the method",
+ e1);
+ } catch (InvocationTargetException e1) {
+ error(
+ "Cannot invoke the onRollback method,the method thrown an exception",
+ e1.getTargetException());
+ }
+ }
+ }
+
+ public void transactionCommitted(Transaction t) {
+ if (m_onRollback != null) {
+ try {
+ m_onCommit.call(new Object[] { t });
+ } catch (NoSuchMethodException e1) {
+ error("Cannot invoke the onCommit callback, method not found",
+ e1);
+ } catch (IllegalAccessException e1) {
+ error(
+ "Cannot invoke the onCommit callback,cannot access the method",
+ e1);
+ } catch (InvocationTargetException e1) {
+ error(
+ "Cannot invoke the onCommit callback,the method thrown an exception",
+ e1.getTargetException());
+ }
+ }
+
+ }
+
+ public void stateChanged(int newState) {
+ if (newState == ComponentInstance.INVALID) {
+ // rollback all owned transactions.
+ for (int i = 0; i < m_methods.size(); i++) {
+ m_methods.get(i).rollbackOwnedTransactions();
+ }
+
+ for (int i =0; i < m_transactions.size(); i++) {
+ try {
+ m_transactions.get(i).setRollbackOnly();
+ } catch (Exception e) {
+ error("Cannot set rollback only on a transaction : " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ public synchronized Object onGet(Object pojo, String fieldName, Object value) {
+ try {
+ if (m_transactionManager != null) {
+ return m_transactionManager.getTransaction();
+ } else {
+ return null;
+ }
+ } catch (SystemException e) {
+ error("Cannot get the current transaction, internal error", e);
+ return null;
+ }
+ }
+
+ public void afterCompletion(int arg0) {
+ try {
+ if (m_transactionManager.getTransaction() != null) {
+ m_transactions .remove(m_transactionManager.getTransaction());
+ if (arg0 == Status.STATUS_ROLLEDBACK) {
+ transactionRolledback(m_transactionManager.getTransaction());
+ } else if (arg0 == Status.STATUS_COMMITTED) {
+ transactionCommitted(m_transactionManager.getTransaction());
+ }
+ }
+ } catch (SystemException e) {
+ error("Cannot remove the transaction from the transaction list : " + e.getMessage());
+ }
+ }
+
+ public void beforeCompletion() {
+
+ }
+
+ public void addTransaction(Transaction transaction) {
+ if (m_transactions.contains(transaction)) {
+ return;
+ }
+ try {
+ transaction.registerSynchronization(this);
+ m_transactions.add(transaction);
+ } catch (Exception e) {
+ error("Cannot add the transaction to the transaction list : " + e.getMessage());
+ }
+ }
+
+ public List<Transaction> getTransactions() {
+ return m_transactions;
+ }
+
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionalMethod.java b/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionalMethod.java
new file mode 100644
index 0000000..df06423
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/src/main/java/org/apache/felix/ipojo/transaction/TransactionalMethod.java
@@ -0,0 +1,306 @@
+/*
+ * 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.transaction;
+
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.felix.ipojo.MethodInterceptor;
+
+public class TransactionalMethod implements MethodInterceptor {
+
+ public static final int REQUIRES = 0;
+
+ public static final int REQUIRES_NEW = 1;
+
+ public static final int MANDATORY = 2;
+
+ public static final int SUPPORTED = 3;
+
+ public static final int NOT_SUPPORTED = 4;
+
+ public static final int NEVER = 5;
+
+ private String method;
+
+ private int propagation;
+
+ private int timeout;
+
+ private List<String> exceptions;
+
+ private TransactionManager manager;
+
+ private Map <Thread, Transaction> m_owned = new HashMap<Thread, Transaction>();
+
+ private boolean exceptionOnRollback;
+
+
+ private TransactionHandler handler;
+
+ private Transaction suspended;
+
+ public TransactionalMethod(String method, int propagation, int timeout, List<String> exception, boolean exceptionOnRollback, TransactionHandler handler) {
+ this.method = method;
+ this.propagation = propagation;
+ this.timeout = timeout;
+ this.exceptions = exception;
+ this.exceptionOnRollback = exceptionOnRollback;
+ this.handler = handler;
+ }
+
+ public synchronized void setTransactionManager(TransactionManager tm) {
+ manager = tm;
+ if (manager == null) {
+ // Clear stored transactions.
+ m_owned.clear();
+
+ }
+ }
+
+
+ public void onEntry() throws SystemException, NotSupportedException {
+ TransactionManager manager = null;
+ synchronized (this) {
+ if (this.manager != null) {
+ manager = this.manager; // Stack confinement
+ } else {
+ return; // Nothing can be done...
+ }
+ }
+
+ Transaction transaction = manager.getTransaction();
+ switch (propagation) {
+ case REQUIRES:
+ // Are we already in a transaction?
+ if (transaction == null) {
+ // No, create one
+ if (timeout > 0) {
+ manager.setTransactionTimeout(timeout);
+ }
+ manager.begin();
+ m_owned.put(Thread.currentThread(), manager.getTransaction());
+ } else {
+ // Add the transaction to the transaction list
+ handler.addTransaction(transaction);
+ }
+ break;
+ case MANDATORY:
+ if (transaction == null) {
+ // Error
+ throw new IllegalStateException("The method " + method + " must be called inside a transaction");
+ } else {
+ // Add the transaction to the transaction list
+ handler.addTransaction(transaction);
+ }
+ break;
+ case SUPPORTED:
+ // if transaction != null, register the callback, else do nothing
+ if (transaction != null) {
+ handler.addTransaction(transaction);
+ } // Else do nothing.
+ break;
+ case NOT_SUPPORTED:
+ // Do nothing.
+ break;
+ case NEVER:
+ if (transaction != null) {
+ throw new IllegalStateException("The method " + method + " must never be called inside a transaction");
+ }
+ break;
+ case REQUIRES_NEW:
+ if (transaction == null) {
+ // No current transaction, Just creates a new one
+ if (timeout > 0) {
+ manager.setTransactionTimeout(timeout);
+ }
+ manager.begin();
+ m_owned.put(Thread.currentThread(), manager.getTransaction());
+ } else {
+ if (suspended == null) {
+ suspended = manager.suspend();
+ if (timeout > 0) {
+ manager.setTransactionTimeout(timeout);
+ }
+ manager.begin();
+ m_owned.put(Thread.currentThread(), manager.getTransaction());
+ } else {
+ throw new IllegalStateException("The method " + method + " requires to suspend a second times a transaction");
+ }
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown or unsupported propagation policy for " + method + " :" + propagation);
+
+ }
+ }
+
+ public void onExit() throws SecurityException, HeuristicMixedException, HeuristicRollbackException, SystemException, InvalidTransactionException, IllegalStateException {
+ switch (propagation) {
+ case REQUIRES:
+ // Are we the owner of the transaction?
+ Transaction transaction = m_owned.get(Thread.currentThread());
+ if (transaction != null) { // Owner.
+ try {
+ transaction.commit(); // Commit the transaction
+ m_owned.remove(Thread.currentThread());
+ handler.transactionCommitted(transaction); // Manage potential notification.
+ } catch ( RollbackException e) {
+ m_owned.remove(Thread.currentThread());
+ // The transaction was rolledback
+ if (exceptionOnRollback) {
+ throw new IllegalStateException("The transaction was rolled back : " + e.getMessage());
+ }
+ handler.transactionRolledback(transaction); // Manage potential notification.
+ }
+ } // Else wait for commit.
+ break;
+ case MANDATORY:
+ // We are never the owner, so just exits the transaction.
+ break;
+ case SUPPORTED:
+ // Do nothing.
+ break;
+ case NOT_SUPPORTED:
+ // Do nothing.
+ break;
+ case NEVER:
+ // Do nothing.
+ break;
+ case REQUIRES_NEW:
+ // We're necessary the owner.
+ transaction = m_owned.get(Thread.currentThread());
+ if (transaction == null) {
+ throw new RuntimeException("Cannot apply the REQUIRES NEW propagation, we're not the transaction owner!");
+ }
+ try {
+ transaction.commit(); // Commit the transaction
+ m_owned.remove(Thread.currentThread());
+ handler.transactionCommitted(transaction); // Manage potential notification.
+ if (suspended != null) {
+ manager.suspend(); // suspend the completed transaction.
+ manager.resume(suspended);
+ suspended = null;
+ }
+ } catch ( RollbackException e) { // The transaction was rolledback rather than committed
+ m_owned.remove(Thread.currentThread());
+ if (suspended != null) {
+ manager.suspend(); // suspend the completed transaction.
+ manager.resume(suspended); // The resume transaction is not rolledback, they are independent.
+ suspended = null;
+ }
+ // The transaction was rolledback
+ if (exceptionOnRollback) {
+ throw new IllegalStateException("The transaction was rolled back : " + e.getMessage());
+ }
+ handler.transactionRolledback(transaction); // Manage potential notification.
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown or unsupported propagation policy for " + method + " :" + propagation);
+
+ }
+ }
+
+ public void onError(String exception) throws SystemException {
+ TransactionManager manager = null;
+ synchronized (this) {
+ if (this.manager != null) {
+ manager = this.manager; // Stack confinement
+ } else {
+ return; // Nothing can be done...
+ }
+ }
+
+ // is the error something to exclude, and are we inside the transaction (owner or participant)?
+ if (! exceptions.contains(exception)) {
+ Transaction tr = manager.getTransaction();
+ if (m_owned.containsValue(tr) || handler.getTransactions().contains(tr)) {
+ // Set the transaction to rollback only
+ manager.getTransaction().setRollbackOnly();
+ }
+ }
+ }
+
+ public void onEntry(Object o, Member member, Object[] objects) {
+ try {
+ onEntry();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("An issue occurs during transaction management of " + method + " : " + e.getMessage());
+ }
+
+ }
+
+ public void onError(Object o, Member member, Throwable throwable) {
+ try {
+ throwable.printStackTrace();
+
+ onError(throwable.getClass().getName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("An issue occurs during transaction management of " + method + " : " + e.getMessage());
+ }
+ }
+
+ public void onExit(Object o, Member member, Object o1) {
+ // Wait for on finally.
+ }
+
+ public void onFinally(Object o, Member member) {
+ try {
+ onExit();
+ } catch (IllegalStateException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("An issue occurs during transaction management of " + method + " : " + e.getMessage());
+ }
+ }
+
+ public void rollbackOwnedTransactions() {
+ Iterator<Entry<Thread, Transaction>> entries = m_owned.entrySet().iterator();
+ while(entries.hasNext()) {
+ Entry<Thread, Transaction> entry = entries.next();
+ try {
+ entry.getValue().rollback();
+ } catch (IllegalStateException e) {
+ throw new RuntimeException("An issue occurs during transaction management of " + method + " : " + e.getMessage());
+ } catch (SystemException e) {
+ throw new RuntimeException("An issue occurs during transaction management of " + method + " : " + e.getMessage());
+ }
+ }
+ m_owned.clear();
+ }
+
+}
diff --git a/ipojo/handler/transaction/transaction-handler/src/main/resources/metadata.xml b/ipojo/handler/transaction/transaction-handler/src/main/resources/metadata.xml
new file mode 100644
index 0000000..8b91423
--- /dev/null
+++ b/ipojo/handler/transaction/transaction-handler/src/main/resources/metadata.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <handler name="transaction" namespace="org.apache.felix.ipojo.transaction"
+ classname="org.apache.felix.ipojo.transaction.TransactionHandler">
+ <requires field="m_transactionManager">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </handler>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/whiteboard/changelog.txt b/ipojo/handler/whiteboard/changelog.txt
new file mode 100644
index 0000000..01992b4
--- /dev/null
+++ b/ipojo/handler/whiteboard/changelog.txt
@@ -0,0 +1,33 @@
+Changes from 1.4.0 to 1.6.0
+----------------------------
+** Bug
+ * [FELIX-2581] - White Board Pattern onActivate called before @Validate
+
+** Improvement
+ * [FELIX-2624] - Support multiple whiteboards using annotations
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-944] - Fix white-board pattern handler symbolic name
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/whiteboard/pom.xml b/ipojo/handler/whiteboard/pom.xml
new file mode 100644
index 0000000..7ee3d57
--- /dev/null
+++ b/ipojo/handler/whiteboard/pom.xml
@@ -0,0 +1,115 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard-handler-project</artifactId>
+ <version>1.6.1-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Whiteboard Handler Project</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>whiteboard-handler</module>
+ <module>whiteboard-handler-it</module>
+ </modules>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>DEPENDENCIES*</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>project</descriptorRef>
+ </descriptorRefs>
+ <!-- we don't want to attach all the assemblies, such as bz2 -->
+ <attach>false</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- only attach the project and bin assemblies, in tar.gz and zip flavors -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-assemblies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.tar.gz
+ </file>
+ <classifier>project</classifier>
+ <type>tar.gz</type>
+ </artifact>
+ <artifact>
+ <file>
+ ${project.build.directory}/${project.artifactId}-${project.version}-project.zip
+ </file>
+ <classifier>project</classifier>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..5748e9c
--- /dev/null
+++ b/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,12 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+
diff --git a/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/whiteboard/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/pom.xml b/ipojo/handler/whiteboard/whiteboard-handler-it/pom.xml
new file mode 100644
index 0000000..b1b17f0
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/pom.xml
@@ -0,0 +1,385 @@
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
+ <name>Apache Felix iPOJO Whiteboard Handler - Integration Test</name>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard-it</artifactId>
+ <version>1.6.1-SNAPSHOT</version>
+
+ <properties>
+ <exam.version>3.0.0</exam.version>
+ <url.version>1.5.1</url.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.6</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude> <!-- Exclude iml files -->
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>regular</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/regular</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>test-all</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ <configuration>
+ <streamLogs>true</streamLogs>
+ <goals>
+ <goal>clean</goal>
+ <goal>test</goal>
+ </goals>
+ <cloneClean>true</cloneClean>
+ </configuration>
+ <executions>
+ <execution>
+ <id>equinox-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>equinox</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/equinox-native</cloneProjectsTo>
+
+ </configuration>
+ </execution>
+ <execution>
+ <id>felix-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>felix</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/felix-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knopflerfish-native</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <profiles>
+ <profile>knopflerfish</profile>
+ </profiles>
+ <cloneProjectsTo>${project.build.directory}/knopflerfish-native</cloneProjectsTo>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.1.v20120830-144521</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+</project>
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/pom.xml b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/pom.xml
new file mode 100644
index 0000000..d9fbae7
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard-it</artifactId>
+ <version>1.6.1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-whiteboard-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooProvider.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooProvider.java
new file mode 100644
index 0000000..1739528
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooProvider.java
@@ -0,0 +1,36 @@
+/*
+ * 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.handler.whiteboard.components;
+
+import org.apache.felix.ipojo.handler.whiteboard.services.FooService;
+
+public class FooProvider implements FooService {
+
+ public String foo;
+
+ public void foo() {
+ if (foo.equals("foo")) {
+ foo = "bar";
+ } else {
+ foo = "foo";
+ }
+ }
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooWhiteBoardPattern.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooWhiteBoardPattern.java
new file mode 100644
index 0000000..a2c80d2
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/components/FooWhiteBoardPattern.java
@@ -0,0 +1,94 @@
+/*
+ * 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.handler.whiteboard.components;
+
+import org.apache.felix.ipojo.handler.whiteboard.services.Observable;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FooWhiteBoardPattern implements Observable {
+
+ List list = new ArrayList();
+ int modifications = 0;
+
+ long validate_time = 0;
+ long first_arrival_time = 0;
+ long first_departure_time = 0;
+ long invalidate_time = 0;
+
+ public void onArrival(ServiceReference ref) {
+ if (first_arrival_time == 0) {
+ first_arrival_time = System.currentTimeMillis();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
+ }
+ list.add(ref);
+ }
+
+ public void onDeparture(ServiceReference ref) {
+ list.remove(ref);
+ if (first_departure_time == 0) {
+ first_departure_time = System.currentTimeMillis();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
+ }
+ }
+
+ public void onModification(ServiceReference ref) {
+ modifications = modifications + 1;
+ }
+
+ public Map getObservations() {
+ Map map = new HashMap();
+ map.put("list", list);
+ map.put("modifications", new Integer(modifications));
+ map.put("validate", new Long(validate_time));
+ map.put("invalidate", new Long(invalidate_time));
+ map.put("arrival", new Long(first_arrival_time));
+ map.put("departure", new Long(first_departure_time));
+ return map;
+ }
+
+ public void start() {
+ if (validate_time == 0) {
+ validate_time = System.currentTimeMillis();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
+ }
+ }
+
+ public void stop() {
+ if (invalidate_time == 0) {
+ invalidate_time = System.currentTimeMillis();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
+ }
+ }
+
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/FooService.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/FooService.java
new file mode 100644
index 0000000..17cc02a
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/FooService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.handler.whiteboard.services;
+
+public interface FooService {
+
+ public void foo();
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/Observable.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/Observable.java
new file mode 100644
index 0000000..084ebdb
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/java/org/apache/felix/ipojo/handler/whiteboard/services/Observable.java
@@ -0,0 +1,28 @@
+/*
+ * 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.handler.whiteboard.services;
+
+import java.util.Map;
+
+public interface Observable {
+
+ public Map getObservations();
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/resources/metadata.xml b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/resources/metadata.xml
new file mode 100644
index 0000000..f294aa6
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/main/resources/metadata.xml
@@ -0,0 +1,65 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:wbp="org.apache.felix.ipojo.whiteboard">
+ <component classname="org.apache.felix.ipojo.handler.whiteboard.components.FooProvider" name="fooprovider">
+ <provides>
+ <property field="foo" value="foo"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.whiteboard.components.FooWhiteBoardPattern" name="under-providers">
+ <wbp:wbp
+ filter="(objectclass=org.apache.felix.ipojo.handler.whiteboard.services.FooService)"
+ onArrival="onArrival" onDeparture="onDeparture" onModification="onModification"
+ />
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.whiteboard.components.FooWhiteBoardPattern" name="under-properties">
+ <wbp:wbp filter="(foo=foo)" onArrival="onArrival" onDeparture="onDeparture"
+ onModification="onModification"
+ />
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.whiteboard.components.FooWhiteBoardPattern" name="under-providers-2">
+ <wbp:whiteboards>
+ <wbp:wbp
+ filter="(objectclass=org.apache.felix.ipojo.handler.whiteboard.services.FooService)"
+ onArrival="onArrival" onDeparture="onDeparture" onModification="onModification"
+ />
+ </wbp:whiteboards>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.handler.whiteboard.components.FooWhiteBoardPattern" name="under-providers-lifecycle">
+ <wbp:wbp
+ filter="(objectclass=org.apache.felix.ipojo.handler.whiteboard.services.FooService)"
+ onArrival="onArrival" onDeparture="onDeparture" onModification="onModification"
+ />
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/Common.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/Common.java
new file mode 100644
index 0000000..e5c6725
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/Common.java
@@ -0,0 +1,216 @@
+/*
+ * 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.handler.whiteboard.test;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * Bootstrap the test from this project
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class Common {
+
+ @Inject
+ BundleContext bc;
+
+ OSGiHelper osgiHelper;
+ IPOJOHelper ipojoHelper;
+
+ Bundle testedBundle;
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(Level.DEBUG);
+
+ return options(
+ cleanCaches(),
+ ipojoBundles(),
+ junitBundles(),
+ testedBundle(),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN")
+ );
+ }
+
+ public static Option junitAndMockitoBundles() {
+ return new DefaultCompositeOption(
+ // Repository required to load harmcrest (OSGi-fied version).
+ repository("http://repository.springsource.com/maven/bundles/external").id(
+ "com.springsource.repository.bundles.external"),
+
+ // Hamcrest with a version matching the range expected by Mockito
+ mavenBundle("org.hamcrest", "com.springsource.org.hamcrest.core", "1.1.0"),
+
+ // Mockito core does not includes Hamcrest
+ mavenBundle("org.mockito", "mockito-core", "1.9.5"),
+
+ // Objenesis with a version matching the range expected by Mockito
+ wrappedBundle(mavenBundle("org.objenesis", "objenesis", "1.2"))
+ .exports("*;version=1.2"),
+
+ // The default JUnit bundle also exports Hamcrest, but with an (incorrect) version of
+ // 4.9 which does not match the Mockito import. When deployed after the hamcrest bundles, it gets
+ // resolved correctly.
+ CoreOptions.junitBundles(),
+
+ /*
+ * Felix has implicit boot delegation enabled by default. It conflicts with Mockito:
+ * java.lang.LinkageError: loader constraint violation in interface itable initialization:
+ * when resolving method "org.osgi.service.useradmin.User$$EnhancerByMockitoWithCGLIB$$dd2f81dc
+ * .newInstance(Lorg/mockito/cglib/proxy/Callback;)Ljava/lang/Object;" the class loader
+ * (instance of org/mockito/internal/creation/jmock/SearchingClassLoader) of the current class,
+ * org/osgi/service/useradmin/User$$EnhancerByMockitoWithCGLIB$$dd2f81dc, and the class loader
+ * (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) for interface
+ * org/mockito/cglib/proxy/Factory have different Class objects for the type org/mockito/cglib/
+ * proxy/Callback used in the signature
+ *
+ * So we disable the bootdelegation. this property has no effect on the other OSGi implementation.
+ */
+ frameworkProperty("felix.bootdelegation.implicit").value("false")
+ );
+ }
+
+ @Before
+ public void commonSetUp() {
+ osgiHelper = new OSGiHelper(bc);
+ ipojoHelper = new IPOJOHelper(bc);
+
+ testedBundle = osgiHelper.getBundle("test.bundle");
+
+ // Dump OSGi Framework information
+ String vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VENDOR);
+ if (vendor == null) {
+ vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_SYMBOLICNAME);
+ }
+ String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
+ System.out.println("OSGi Framework : " + vendor + " - " + version);
+ }
+
+ @After
+ public void commonTearDown() {
+ ipojoHelper.dispose();
+ osgiHelper.dispose();
+ }
+
+ public static CompositeOption ipojoBundles() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo").versionAsInProject(),
+ mavenBundle("org.ow2.chameleon.testing", "osgi-helpers").versionAsInProject(),
+ // The tested handler
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.whiteboard").versionAsInProject()
+ );
+ }
+
+ public Option testedBundle() throws MalformedURLException {
+ File out = new File("target/tested/bundle.jar");
+
+ TinyBundle tested = TinyBundles.bundle();
+
+ // We look inside target/classes to find the class and resources
+ File classes = new File("target/classes");
+ Collection<File> files = FileUtils.listFilesAndDirs(classes, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
+ List<File> services = new ArrayList<File>();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // By convention we export of .services and .service package
+ if (file.getName().endsWith("services") || file.getName().endsWith("service")) {
+ services.add(file);
+ }
+ } else {
+ // We need to compute the path
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ tested.add(path, file.toURI().toURL());
+ System.out.println(file.getName() + " added to " + path);
+ }
+ }
+
+ String export = "";
+ for (File file : services) {
+ if (export.length() > 0) { export += ", "; }
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ String packageName = path.replace('/', '.');
+ export += packageName;
+ }
+
+ System.out.println("Exported packages : " + export);
+
+ InputStream inputStream = tested
+ .set(Constants.BUNDLE_SYMBOLICNAME, "test.bundle")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ .set(Constants.EXPORT_PACKAGE, export)
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources")));
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the manipulated bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the manipulated bundle");
+ }
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/TestWhiteboardPatternHandler.java b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/TestWhiteboardPatternHandler.java
new file mode 100644
index 0000000..ae8e9c2
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/it/whiteboard-it/src/test/java/org/apache/felix/ipojo/handler/whiteboard/test/TestWhiteboardPatternHandler.java
@@ -0,0 +1,302 @@
+/*
+ * 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.handler.whiteboard.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.handler.whiteboard.services.FooService;
+import org.apache.felix.ipojo.handler.whiteboard.services.Observable;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestWhiteboardPatternHandler extends Common {
+
+ Factory provFactory;
+ Factory factory, factory2, factory3, factory4;
+
+ @Before
+ public void setUp() {
+ provFactory = ipojoHelper.getFactory("fooprovider");
+ factory = ipojoHelper.getFactory("under-providers");
+ factory2 = ipojoHelper.getFactory("under-properties");
+ factory3 = ipojoHelper.getFactory("under-providers-lifecycle");
+ factory4 = ipojoHelper.getFactory("under-providers-2");
+ }
+
+ @Test
+ public void testServiceProviders() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = factory.createComponentInstance(new Properties());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Observable.class.getName(), ci.getInstanceName());
+ assertNotNull("Check Observable availability", ref);
+ Observable obs = (Observable) osgiHelper.getServiceObject(ref);
+
+ Map map = obs.getObservations();
+ assertEquals("Check empty list", ((List) map.get("list")).size(), 0);
+
+ Properties p1 = new Properties();
+ p1.put("foo", "foo");
+ ComponentInstance prov1 = provFactory.createComponentInstance(p1);
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+
+ Properties p2 = new Properties();
+ p2.put("foo", "foo");
+ ComponentInstance prov2 = provFactory.createComponentInstance(p2);
+
+ map = obs.getObservations();
+ assertEquals("Check list #2", ((List) map.get("list")).size(), 2);
+
+ prov1.stop();
+
+ map = obs.getObservations();
+ assertEquals("(1) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov2.stop();
+
+ map = obs.getObservations();
+ assertEquals("(2) Check list #0", ((List) map.get("list")).size(), 0);
+
+ prov2.start();
+
+ map = obs.getObservations();
+ assertEquals("(3) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov1.start();
+
+ map = obs.getObservations();
+ assertEquals("(4) Check list #2", ((List) map.get("list")).size(), 2);
+
+ prov1.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(5) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov2.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(6) Check list #0", ((List) map.get("list")).size(), 0);
+
+ bc.ungetService(ref);
+ ci.dispose();
+ }
+
+ @Test
+ public void testPropertiesProviders() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = factory2.createComponentInstance(new Properties());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Observable.class.getName(), ci.getInstanceName());
+ assertNotNull("Check Observable availability", ref);
+ Observable obs = (Observable) osgiHelper.getServiceObject(ref);
+
+ Map map = obs.getObservations();
+ assertEquals("Check empty list", ((List) map.get("list")).size(), 0);
+
+ Properties p1 = new Properties();
+ p1.put("foo", "foo");
+ ComponentInstance prov1 = provFactory.createComponentInstance(p1);
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov1.getInstanceName());
+ FooService fs1 = (FooService) osgiHelper.getServiceObject(ref1);
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+
+ Properties p2 = new Properties();
+ p2.put("foo", "foo");
+ ComponentInstance prov2 = provFactory.createComponentInstance(p2);
+ ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ FooService fs2 = (FooService) osgiHelper.getServiceObject(ref2);
+
+ map = obs.getObservations();
+ assertEquals("Check list #2", ((List) map.get("list")).size(), 2);
+
+ fs1.foo();
+
+ map = obs.getObservations();
+ assertEquals("(1) Check list #1", ((List) map.get("list")).size(), 1);
+
+ fs2.foo();
+
+ map = obs.getObservations();
+ assertEquals("(2) Check list #0", ((List) map.get("list")).size(), 0);
+
+ fs2.foo();
+
+ map = obs.getObservations();
+ assertEquals("(3) Check list #1", ((List) map.get("list")).size(), 1);
+
+ fs1.foo();
+
+ map = obs.getObservations();
+ assertEquals("(4) Check list #2", ((List) map.get("list")).size(), 2);
+
+ prov1.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(5) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov2.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(6) Check list #0", ((List) map.get("list")).size(), 0);
+
+ bc.ungetService(ref1);
+ bc.ungetService(ref2);
+ bc.ungetService(ref);
+ ci.dispose();
+ }
+
+ @Test
+ public void testModifications() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = factory.createComponentInstance(new Properties());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Observable.class.getName(), ci.getInstanceName());
+ assertNotNull("Check Observable availability", ref);
+ Observable obs = (Observable) osgiHelper.getServiceObject(ref);
+
+ Map map = obs.getObservations();
+ assertEquals("Check empty list", ((List) map.get("list")).size(), 0);
+
+ Properties p1 = new Properties();
+ p1.put("foo", "foo");
+ ComponentInstance prov1 = provFactory.createComponentInstance(p1);
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+ assertEquals("Check modification #0", ((Integer) map.get("modifications")).intValue(), 0);
+
+ ServiceReference ref2 = osgiHelper.getServiceReference(FooService.class.getName(), null);
+ assertNotNull("Check FooService availability", ref2);
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref2);
+ fs.foo();
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+ assertEquals("Check modification #1 (" + map.get("modifications") + ")", ((Integer) map.get("modifications")).intValue(), 1);
+
+ fs.foo();
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+ assertEquals("Check modification #2", ((Integer) map.get("modifications")).intValue(), 2);
+
+ prov1.dispose();
+ map = obs.getObservations();
+ assertEquals("Check list #0", ((List) map.get("list")).size(), 0);
+ assertEquals("Check modification #2", ((Integer) map.get("modifications")).intValue(), 2);
+
+ bc.ungetService(ref);
+ bc.ungetService(ref2);
+ ci.dispose();
+ }
+
+ @Test
+ public void testLifecycleCompliance() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // First expose a service.
+ Properties p1 = new Properties();
+ p1.put("foo", "foo");
+ ComponentInstance prov1 = provFactory.createComponentInstance(p1);
+
+ ComponentInstance ci = factory3.createComponentInstance(new Properties());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Observable.class.getName(), ci.getInstanceName());
+ assertNotNull("Check Observable availability", ref);
+ Observable obs = (Observable) osgiHelper.getServiceObject(ref);
+
+ Map map = obs.getObservations();
+ // Check time
+ Long validate = (Long) map.get("validate");
+ Long arrival = (Long) map.get("arrival");
+
+ // Validate must be call before.
+ assertTrue(validate + " <?> " + arrival, validate < arrival);
+
+ prov1.dispose();
+ ci.dispose();
+
+ }
+
+ @Test
+ public void testServiceProvidersWhiteWhiteboards() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = factory4.createComponentInstance(new Properties());
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Observable.class.getName(), ci.getInstanceName());
+ assertNotNull("Check Observable availability", ref);
+ Observable obs = (Observable) osgiHelper.getServiceObject(ref);
+
+ Map map = obs.getObservations();
+ assertEquals("Check empty list", ((List) map.get("list")).size(), 0);
+
+ Properties p1 = new Properties();
+ p1.put("foo", "foo");
+ ComponentInstance prov1 = provFactory.createComponentInstance(p1);
+
+ map = obs.getObservations();
+ assertEquals("Check list #1", ((List) map.get("list")).size(), 1);
+
+ Properties p2 = new Properties();
+ p2.put("foo", "foo");
+ ComponentInstance prov2 = provFactory.createComponentInstance(p2);
+
+ map = obs.getObservations();
+ assertEquals("Check list #2", ((List) map.get("list")).size(), 2);
+
+ prov1.stop();
+
+ map = obs.getObservations();
+ assertEquals("(1) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov2.stop();
+
+ map = obs.getObservations();
+ assertEquals("(2) Check list #0", ((List) map.get("list")).size(), 0);
+
+ prov2.start();
+
+ map = obs.getObservations();
+ assertEquals("(3) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov1.start();
+
+ map = obs.getObservations();
+ assertEquals("(4) Check list #2", ((List) map.get("list")).size(), 2);
+
+ prov1.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(5) Check list #1", ((List) map.get("list")).size(), 1);
+
+ prov2.dispose();
+
+ map = obs.getObservations();
+ assertEquals("(6) Check list #0", ((List) map.get("list")).size(), 0);
+
+ bc.ungetService(ref);
+ ci.dispose();
+ }
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/changelog.txt b/ipojo/handler/whiteboard/whiteboard-handler/changelog.txt
new file mode 100644
index 0000000..01992b4
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/changelog.txt
@@ -0,0 +1,33 @@
+Changes from 1.4.0 to 1.6.0
+----------------------------
+** Bug
+ * [FELIX-2581] - White Board Pattern onActivate called before @Validate
+
+** Improvement
+ * [FELIX-2624] - Support multiple whiteboards using annotations
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-944] - Fix white-board pattern handler symbolic name
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/metadata.xml b/ipojo/handler/whiteboard/whiteboard-handler/metadata.xml
new file mode 100644
index 0000000..88eec46
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/metadata.xml
@@ -0,0 +1,30 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <handler
+ classname="org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler"
+ name="wbp" namespace="org.apache.felix.ipojo.whiteboard">
+ </handler>
+
+ <!-- Alternative handler for component using the @Whiteboards annotation -->
+ <handler
+ classname="org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler"
+ name="whiteboards" namespace="org.apache.felix.ipojo.whiteboard">
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/obr.xml b/ipojo/handler/whiteboard/whiteboard-handler/obr.xml
new file mode 100644
index 0000000..2da24fa
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/obr.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="wbp"/>
+ <p n="namespace" v="org.apache.felix.ipojo.whiteboard"/>
+ <p n="type" v="primitive"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/pom.xml b/ipojo/handler/whiteboard/whiteboard-handler/pom.xml
new file mode 100644
index 0000000..e6bf2ed
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/pom.xml
@@ -0,0 +1,103 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO White Board Pattern Handler</name>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard</artifactId>
+ <groupId>org.apache.felix</groupId>
+ <version>1.6.1-SNAPSHOT</version>
+
+ <description>
+ iPOJO extension to easily implement a white-board pattern (host).
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/white-board-pattern-handler.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.6.4</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO White-Board Pattern Handler
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/white-board-pattern-handler.html
+ </Bundle-DocURL>
+ <Private-Package>org.apache.felix.ipojo.handler.wbp
+ </Private-Package>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.6.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <metadata>metadata.xml</metadata>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/NOTICE b/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardManager.java b/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardManager.java
new file mode 100644
index 0000000..8e0da46
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardManager.java
@@ -0,0 +1,174 @@
+/*
+ * 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.handler.wbp;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Tracker;
+import org.apache.felix.ipojo.util.TrackerCustomizer;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Manage a white board pattern.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class WhiteBoardManager implements TrackerCustomizer {
+
+ /**
+ * The monitored filter.
+ */
+ private Filter m_filter;
+
+ /**
+ * The onArrival method.
+ */
+ private Callback m_onArrival;
+
+ /**
+ * The onDeparture method.
+ */
+ private Callback m_onDeparture;
+
+ /**
+ * The onModify method.
+ */
+ private Callback m_onModification;
+
+ /**
+ * The service tracker.
+ */
+ private Tracker m_tracker;
+
+ /**
+ * The attached handler.
+ */
+ private PrimitiveHandler m_handler;
+
+ /**
+ * Constructor.
+ * @param handler the attached handler
+ * @param filter the monitored filter
+ * @param bind the onArrival method
+ * @param unbind the onDeparture method
+ * @param modification the onModify method
+ */
+ public WhiteBoardManager(WhiteBoardPatternHandler handler, Filter filter, String bind, String unbind, String modification) {
+ m_handler = handler;
+ m_onArrival = new Callback(bind, new Class[] {ServiceReference.class}, false, m_handler.getInstanceManager());
+ m_onDeparture = new Callback(unbind, new Class[] {ServiceReference.class}, false, m_handler.getInstanceManager());
+ if (modification != null) {
+ m_onModification = new Callback(modification, new Class[] {ServiceReference.class}, false, m_handler.getInstanceManager());
+ }
+ m_filter = filter;
+ m_tracker = new Tracker(handler.getInstanceManager().getContext(), m_filter, this);
+ }
+
+
+
+ /**
+ * Opens the tracker.
+ */
+ public void start() {
+ // Calling several times open is no-effect.
+ m_tracker.open();
+ }
+
+ /**
+ * Closes the tracker.
+ */
+ public void stop() {
+ m_tracker.close();
+ }
+
+ /**
+ * A new service was added to the tracker.
+ * @param arg0 the service reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void addedService(ServiceReference arg0) {
+ try {
+ m_onArrival.call(new Object[] {arg0});
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " does not exist in the class", e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " cannot be invoked", e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The onArrival method " + m_onArrival.getMethod() + " has thrown an exception", e
+ .getTargetException());
+ }
+ }
+
+ /**
+ * A new service is detected.
+ * @param arg0 the service reference
+ * @return {@code true} to add the service.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+ */
+ public boolean addingService(ServiceReference arg0) {
+ return true;
+ }
+
+ /**
+ * An existing service was modified.
+ * @param arg0 the service reference
+ * @param arg1 the service object (if already get)
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void modifiedService(ServiceReference arg0, Object arg1) {
+ if (m_onModification != null) {
+ try {
+ m_onModification.call(new Object[] {arg0});
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The onModification method " + m_onModification.getMethod() + " does not exist in the class", e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The onModification method " + m_onModification.getMethod() + " cannot be invoked", e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The onModification method " + m_onModification.getMethod() + " has thrown an exception", e.getTargetException());
+ }
+ }
+ }
+
+ /**
+ * A service disappears.
+ * @param arg0 the service reference
+ * @param arg1 the service object (if already get)
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void removedService(ServiceReference arg0, Object arg1) {
+ try {
+ m_onDeparture.call(new Object[] {arg0});
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " does not exist in the class", e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " cannot be invoked", e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The onDeparture method " + m_onDeparture.getMethod() + " has thrown an exception", e.getTargetException());
+ }
+ }
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardPatternHandler.java b/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardPatternHandler.java
new file mode 100644
index 0000000..70a880e
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/src/main/java/org/apache/felix/ipojo/handler/wbp/WhiteBoardPatternHandler.java
@@ -0,0 +1,131 @@
+/*
+ * 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.handler.wbp;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * White board pattern handler.
+ * This handler aims to automate white board patterns by invoking callback when needed.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class WhiteBoardPatternHandler extends PrimitiveHandler {
+
+ /**
+ * The handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.whiteboard";
+
+ /**
+ * The white board pattern to manage. By default just one.
+ */
+ private List m_managers = new ArrayList(1);
+
+ /**
+ * Configure method. Parses the metadata to analyze white-board-pattern elements.
+ * @param elem the component type description
+ * @param dict the instance description
+ * @throws ConfigurationException if the description is not valid.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element elem, Dictionary dict) throws ConfigurationException {
+
+ // There is two way to configure the handler :
+ // - the wbp elements
+ // - the whiteboards elements
+ Element[] elems = elem.getElements("wbp", NAMESPACE);
+
+ if (elems == null || elems.length == 0) {
+ // Alternative way
+ Element[] whiteboards = elem.getElements("whiteboards", NAMESPACE);
+ if (whiteboards == null) {
+ throw new ConfigurationException("Cannot configure the whiteboard pattern handler - no suitable configuration found");
+ } else {
+ elems = whiteboards[0].getElements("wbp", NAMESPACE);
+ }
+ }
+
+ // Last check.
+ if (elems == null) {
+ throw new ConfigurationException("Cannot configure the whiteboard pattern handler - no suitable configuration found");
+ }
+
+ for (int i = 0; i < elems.length; i++) {
+ String filter = elems[i].getAttribute("filter");
+ String onArrival = elems[i].getAttribute("onArrival");
+ String onDeparture = elems[i].getAttribute("onDeparture");
+ String onModification = elems[i].getAttribute("onModification");
+
+ if (filter == null) {
+ throw new ConfigurationException("The white board pattern element requires a filter attribute");
+ }
+ if (onArrival == null || onDeparture == null) {
+ throw new ConfigurationException("The white board pattern element requires the onArrival and onDeparture attributes");
+ }
+
+ try {
+ WhiteBoardManager wbm = new WhiteBoardManager(this, getInstanceManager().getContext().createFilter(filter), onArrival, onDeparture, onModification);
+ m_managers.add(wbm);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("The filter " + filter + " is invalid : " + e);
+ }
+ }
+
+ }
+
+ /**
+ * Start method.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ }
+
+
+
+ /**
+ * Start managers if we're valid.
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ if (state == ComponentInstance.VALID) {
+ for (int i = 0; i < m_managers.size(); i++) {
+ ((WhiteBoardManager) m_managers.get(i)).start();
+ }
+ }
+ }
+
+ /**
+ * Stop method. Stops managers.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_managers.size(); i++) {
+ ((WhiteBoardManager) m_managers.get(i)).stop();
+ }
+ }
+
+}
diff --git a/ipojo/handler/whiteboard/whiteboard-handler/src/main/resources/whiteboard-pattern.xsd b/ipojo/handler/whiteboard/whiteboard-handler/src/main/resources/whiteboard-pattern.xsd
new file mode 100644
index 0000000..f02afde
--- /dev/null
+++ b/ipojo/handler/whiteboard/whiteboard-handler/src/main/resources/whiteboard-pattern.xsd
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.whiteboard"
+ xmlns="org.apache.felix.ipojo.whiteboard"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="wbp" type="WBPType"></xs:element>
+ <xs:complexType name="WBPType">
+ <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
diff --git a/ipojo/junit4osgi/felix-command/LICENSE b/ipojo/junit4osgi/felix-command/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/ipojo/junit4osgi/felix-command/NOTICE b/ipojo/junit4osgi/felix-command/NOTICE
new file mode 100644
index 0000000..96ef392
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/NOTICE
@@ -0,0 +1,28 @@
+Apache Felix iPOJO junit4osgi Felix Command
+Copyright 2008-2009 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+This product uses software developed by
+Junit project (http://junit.org)
+Licensed under Common Public License 1.0.
+
+III. License Summary
+- Apache License 2.0
+- Common Public License 1.0
+
diff --git a/ipojo/junit4osgi/felix-command/doc/changelog.txt b/ipojo/junit4osgi/felix-command/doc/changelog.txt
new file mode 100644
index 0000000..524e88b
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/doc/changelog.txt
@@ -0,0 +1,3 @@
+Version 1.0.0
+-------------
+ * Initial release
\ No newline at end of file
diff --git a/ipojo/junit4osgi/felix-command/metadata.xml b/ipojo/junit4osgi/felix-command/metadata.xml
new file mode 100644
index 0000000..b1524c5
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/metadata.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<iPOJO>
+ <component
+ className="org.apache.felix.ipojo.junit4osgi.command.JunitCommand"
+ factory="false">
+ <requires field="m_runner" />
+ <provides />
+ </component>
+ <instance
+ component="org.apache.felix.ipojo.junit4osgi.command.JunitCommand" />
+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/junit4osgi/felix-command/pom.xml b/ipojo/junit4osgi/felix-command/pom.xml
new file mode 100644
index 0000000..4e9dca1
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/pom.xml
@@ -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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Junit4Osgi-Felix-Command</name>
+ <artifactId>
+ org.apache.felix.ipojo.junit4osgi.felix-command
+ </artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.shell</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.4</source>
+ <target>1.4</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.5</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name> Apache Felix iPOJO OSGi Junit Runner - Felix Command
+ </Bundle-Name>
+ <Bundle-SymbolicName> ${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package> org.apache.felix.ipojo.junit4osgi.command
+ </Private-Package>
+ <Include-Resource> META-INF/LICENSE=LICENSE,
+ META-INF/NOTICE=NOTICE </Include-Resource>
+ <_plugin>org.apache.felix.ipojo.bnd.PojoizationPlugin;metadata=${basedir}/metadata.xml;use-local-schemas=true</_plugin>
+ </instructions>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin
+ </artifactId>
+ <configuration>
+ <configLocation>
+ http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml
+ </configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.java b/ipojo/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.java
new file mode 100644
index 0000000..da52feb
--- /dev/null
+++ b/ipojo/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.java
@@ -0,0 +1,140 @@
+/*
+ * 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.junit4osgi.command;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+import org.apache.felix.shell.Command;
+
+/**
+ * Felix shell command. Allow to run tests.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JunitCommand implements Command {
+
+ /**
+ * OSGi Junit Runner service.
+ */
+ private OSGiJunitRunner m_runner;
+
+ /**
+ * Gets the Test names.
+ * @param list the list of test
+ * @return the list of test names.
+ */
+ private List getNamesFromTests(List list) {
+ List names = new ArrayList(list.size());
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i) instanceof TestCase) {
+ names.add(((TestCase) list.get(i)).getName());
+ }
+ if (list.get(i) instanceof TestSuite) {
+ String name = ((TestSuite) list.get(i)).getName();
+ if (name == null) {
+ name = ((TestSuite) list.get(i)).toString();
+ }
+ names.add(name);
+ }
+ }
+ return names;
+ }
+
+ /**
+ * Executes the command.
+ * @param line the command line
+ * @param out the output stream
+ * @param err the error stream
+ * @see org.apache.felix.shell.Command#execute(java.lang.String, java.io.PrintStream, java.io.PrintStream)
+ */
+ public void execute(String line, PrintStream out, PrintStream err) {
+ line = line.substring(getName().length()).trim();
+ List tr = null;
+ if (line.equals("all")) {
+ if (m_runner.getTests() == null) {
+ err.println("No tests to execute");
+ return;
+ } else {
+ out.println("Executing " + getNamesFromTests(m_runner.getTests()));
+ tr = m_runner.run();
+ }
+ } else {
+ try {
+ Long bundleId = new Long(line);
+ if (m_runner.getTests(bundleId.longValue()) == null) {
+ err.println("No tests to execute");
+ return;
+ } else {
+ out.println("Executing " + getNamesFromTests(m_runner.getTests(bundleId.longValue())));
+ tr = m_runner.run(bundleId.longValue());
+ }
+ } catch (NumberFormatException e) {
+ err.println("Unable to parse id " + line);
+ return;
+ }
+ }
+
+ ListIterator it = tr.listIterator();
+ while (it.hasNext()) {
+ TestResult result = (TestResult) it.next();
+ if (result.failureCount() != 0) {
+ TestFailure fail = (TestFailure) result.failures().nextElement();
+ out.println(fail.trace());
+ return;
+ }
+ }
+
+ }
+
+ /**
+ * Gets the command name.
+ * @return "junit"
+ * @see org.apache.felix.shell.Command#getName()
+ */
+ public String getName() {
+ return "junit";
+ }
+
+ /**
+ * Gets a small description of the command.
+ * @return "launch junit tests"
+ * @see org.apache.felix.shell.Command#getShortDescription()
+ */
+ public String getShortDescription() {
+ return "launch junit tests";
+ }
+
+ /**
+ * Gets command usage.
+ * @return the command usage.
+ * @see org.apache.felix.shell.Command#getUsage()
+ */
+ public String getUsage() {
+ return "junit <bundleid> | junit all";
+ }
+
+}
diff --git a/ipojo/junit4osgi/immediate-launcher/LICENSE b/ipojo/junit4osgi/immediate-launcher/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/junit4osgi/immediate-launcher/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/ipojo/junit4osgi/immediate-launcher/NOTICE b/ipojo/junit4osgi/immediate-launcher/NOTICE
new file mode 100644
index 0000000..986cc71
--- /dev/null
+++ b/ipojo/junit4osgi/immediate-launcher/NOTICE
@@ -0,0 +1,27 @@
+Apache Felix iPOJO junit4osgi Immediate Runner
+Copyright 2008-2009 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+This product uses software developed by
+Junit project (http://junit.org)
+Licensed under Common Public License 1.0.
+
+III. License Summary
+- Apache License 2.0
+- Common Public License 1.0
diff --git a/ipojo/junit4osgi/immediate-launcher/metadata.xml b/ipojo/junit4osgi/immediate-launcher/metadata.xml
new file mode 100644
index 0000000..9f3da35
--- /dev/null
+++ b/ipojo/junit4osgi/immediate-launcher/metadata.xml
@@ -0,0 +1,29 @@
+<!--
+ 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.
+-->
+<iPOJO>
+ <component
+ className="org.apache.felix.ipojo.junit4osgi.command.ImmediateRunner"
+ factory="false">
+ <requires field="m_runner" />
+ <callback method="start" transition="validate" />
+ </component>
+ <instance
+ component="org.apache.felix.ipojo.junit4osgi.command.ImmediateRunner"
+ name="immediate-runner" />
+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/junit4osgi/immediate-launcher/pom.xml b/ipojo/junit4osgi/immediate-launcher/pom.xml
new file mode 100644
index 0000000..771ddda
--- /dev/null
+++ b/ipojo/junit4osgi/immediate-launcher/pom.xml
@@ -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.
+-->
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Junit4Osgi-Immediate-Runner</name>
+ <artifactId>
+ org.apache.felix.ipojo.junit4osgi.immediate-runner
+ </artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.shell</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.5</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name> Apache Felix iPOJO OSGi Junit Runner - Immediate Runner
+ </Bundle-Name>
+ <Bundle-SymbolicName> ${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package> org.apache.felix.ipojo.junit4osgi.command
+ </Private-Package>
+ <Include-Resource> META-INF/LICENSE=LICENSE,
+ META-INF/NOTICE=NOTICE </Include-Resource>
+ <_plugin>org.apache.felix.ipojo.bnd.PojoizationPlugin;metadata=${basedir}/metadata.xml;use-local-schemas=true</_plugin>
+ </instructions>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin
+ </artifactId>
+ <configuration>
+ <configLocation>
+ http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml
+ </configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.java b/ipojo/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.java
new file mode 100644
index 0000000..1cc0a59
--- /dev/null
+++ b/ipojo/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.java
@@ -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.
+ */
+package org.apache.felix.ipojo.junit4osgi.command;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+
+/**
+ * Junit Immediate runner.
+ * Executes test when starts.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ImmediateRunner {
+
+ /**
+ * OSGi Junit Runner service.
+ */
+ private OSGiJunitRunner m_runner;
+
+ /**
+ * Start method.
+ */
+ public void start() {
+ m_runner.run();
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/LICENSE b/ipojo/junit4osgi/junit4osgi/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/ipojo/junit4osgi/junit4osgi/LICENSE.junit b/ipojo/junit4osgi/junit4osgi/LICENSE.junit
new file mode 100644
index 0000000..4fbc2f9
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/LICENSE.junit
@@ -0,0 +1,86 @@
+Common Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
+ b) in the case of each subsequent Contributor:
+
+ i) changes to the Program, and
+
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+
+ b) its license agreement:
+
+ i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
+
+ ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
+
+ iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
+
+ iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+
+ b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
\ No newline at end of file
diff --git a/ipojo/junit4osgi/junit4osgi/NOTICE b/ipojo/junit4osgi/junit4osgi/NOTICE
new file mode 100644
index 0000000..d696f41
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/NOTICE
@@ -0,0 +1,27 @@
+Apache Felix iPOJO junit4osgi Framework
+Copyright 2008-2009 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed by
+Junit project (http://junit.org)
+Licensed under Common Public License 1.0.
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+III. License Summary
+- Apache License 2.0
+- Common Public License 1.0
diff --git a/ipojo/junit4osgi/junit4osgi/doc/changelog.txt b/ipojo/junit4osgi/junit4osgi/doc/changelog.txt
new file mode 100644
index 0000000..524e88b
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/doc/changelog.txt
@@ -0,0 +1,3 @@
+Version 1.0.0
+-------------
+ * Initial release
\ No newline at end of file
diff --git a/ipojo/junit4osgi/junit4osgi/metadata.xml b/ipojo/junit4osgi/junit4osgi/metadata.xml
new file mode 100644
index 0000000..045e20c
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/metadata.xml
@@ -0,0 +1,36 @@
+<!--
+ 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.
+-->
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd
+ org.apache.felix.ipojo.extender http://felix.apache.org/ipojo/schemas/CURRENT/extender-pattern.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:extender="org.apache.felix.ipojo.extender">
+ <component
+ classname="org.apache.felix.ipojo.junit4osgi.impl.JunitExtender">
+ <extender:extender extension="Test-Suite"
+ onArrival="onBundleArrival" onDeparture="onBundleDeparture" />
+ <callback transition="invalidate" method="stopping" />
+ <callback transition="validate" method="starting" />
+ <requires field="m_log" optional="true"
+ default-implementation="org.apache.felix.ipojo.junit4osgi.impl.LogServiceImpl"/>
+ <provides />
+ </component>
+ <instance
+ component="org.apache.felix.ipojo.junit4osgi.impl.JunitExtender" />
+</ipojo>
diff --git a/ipojo/junit4osgi/junit4osgi/pom.xml b/ipojo/junit4osgi/junit4osgi/pom.xml
new file mode 100644
index 0000000..e086c87
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/pom.xml
@@ -0,0 +1,152 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Junit4Osgi</name>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.4</source>
+ <target>1.4</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.5</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>
+ Apache Felix iPOJO OSGi Junit Runner
+ </Bundle-Name>
+ <Bundle-SymbolicName>
+ ${project.artifactId}
+ </Bundle-SymbolicName>
+ <Private-Package>
+ org.apache.felix.ipojo.junit4osgi.impl,
+ org.apache.felix.ipojo.junit4osgi.test,
+ </Private-Package>
+ <Export-Package>
+ org.apache.felix.ipojo.junit4osgi,
+ org.apache.felix.ipojo.junit4osgi.helpers,
+ junit.*
+ </Export-Package>
+ <Import-Package>!javax.swing*, *</Import-Package>
+ <Test-Suite>
+ org.apache.felix.ipojo.junit4osgi.test.TestTestCase,
+ org.apache.felix.ipojo.junit4osgi.test.TestOSGiTestCase,
+ org.apache.felix.ipojo.junit4osgi.test.TestTestSuite,
+ org.apache.felix.ipojo.junit4osgi.test.TestOSGiTestSuite,
+ </Test-Suite>
+ <Include-Resource>
+ META-INF/LICENSE=LICENSE,
+ META-INF/LICENSE.junit=LICENSE.junit,
+ META-INF/NOTICE=NOTICE
+ </Include-Resource>
+ <_plugin>
+ org.apache.felix.ipojo.bnd.PojoizationPlugin;metadata=${basedir}/metadata.xml;use-local-schemas=true
+ </_plugin>
+ </instructions>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <!--
+ Use the BND-iPOJO-Plugin
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>-->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ <violationSeverity>error</violationSeverity>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/Helper.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/Helper.java
new file mode 100644
index 0000000..9909b68
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/Helper.java
@@ -0,0 +1,58 @@
+/*
+ * 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.junit4osgi;
+
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * Helper abstract class.
+ * Helper objects aim to facilitate Test writing.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class Helper {
+
+ /**
+ * The bundle context.
+ */
+ protected BundleContext m_context;
+
+ /**
+ * The OSGi Test case.
+ */
+ protected OSGiTestCase m_testcase;
+
+ /**
+ * Creates a Helper.
+ * Registers the helper.
+ * Sub-classes must initialize the session.
+ * @param tc the OSGi Test Case
+ */
+ public Helper(OSGiTestCase tc) {
+ m_testcase = tc;
+ m_context = m_testcase.getBundleContext();
+ tc.addHelper(this);
+ }
+
+ /**
+ * Rolls back the session.
+ */
+ public abstract void dispose();
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiJunitRunner.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiJunitRunner.java
new file mode 100644
index 0000000..334e311
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiJunitRunner.java
@@ -0,0 +1,72 @@
+/*
+ * 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.junit4osgi;
+
+import java.io.PrintStream;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+/**
+ * OSGi Junit Runner.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface OSGiJunitRunner {
+
+ /**
+ * Set the output stream of the runner.
+ * @param ps the print stream.
+ */
+ void setResultPrinter(PrintStream ps);
+
+ /**
+ * Run the tests.
+ * @return the list of TestResult.
+ */
+ List/*<TestResult>*/ run();
+
+ /**
+ * Run the tests from the given bundle.
+ * @param bundleId the bundle id containing the tests.
+ * @return the list of the test results.
+ */
+ List/*<TestResult>*/ run(long bundleId);
+
+ /**
+ * Get the list of available test suites.
+ * @return the list of Test objects.
+ */
+ List/*<Test>*/ getTests();
+
+ /**
+ * Get the tests from the given bundle.
+ * @param bundleId the bundle id.
+ * @return the list of Test contained in the given bundle.
+ */
+ List/*<Test>*/ getTests(long bundleId);
+
+ /**
+ * Run the given test.
+ * @param test the test to execute.
+ * @return the result.
+ */
+ TestResult run(Test test);
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.java
new file mode 100644
index 0000000..9599974
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.java
@@ -0,0 +1,782 @@
+/*
+ * 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.junit4osgi;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * OSGi Test Case.
+ * Allows the injection of the bundle context.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class OSGiTestCase extends TestCase {
+
+ /**
+ * The bundle context.
+ */
+ protected BundleContext context;
+
+ /**
+ * List of get references.
+ */
+ private List m_references = new ArrayList();
+
+ /**
+ * List of helpers.
+ */
+ private List m_helpers = new ArrayList();
+
+ /**
+ * Gets the Bundle Context.
+ * @return the bundle context.
+ */
+ public BundleContext getContext() {
+ return context;
+ }
+
+ /**
+ * Add an helper.
+ * This method is called by the {@link Helper#Helper(OSGiTestCase)}
+ * method.
+ * @param helper the helper object.
+ */
+ public void addHelper(Helper helper) {
+ m_helpers.add(helper);
+ }
+
+ /**
+ * Extends runBare to release (unget) services after the teardown.
+ * @throws Throwable when an error occurs.
+ * @see junit.framework.TestCase#runBare()
+ */
+ public void runBare() throws Throwable {
+ setUp();
+ try {
+ runTest();
+ } finally {
+ tearDown();
+ // Stop Helpers
+ for (int i = 0; i < m_helpers.size(); i++) {
+ ((Helper) m_helpers.get(i)).dispose();
+ }
+ // Unget services
+ for (int i = 0; i < m_references.size(); i++) {
+ context.ungetService((ServiceReference) m_references.get(i));
+ }
+ m_references.clear();
+ }
+
+ }
+
+ public void setBundleContext(BundleContext bc) {
+ context = bc;
+ }
+
+ public BundleContext getBundleContext() {
+ return context;
+ }
+
+ /**
+ * Checks that the given string is contained in the given array.
+ * @param message the assert point message
+ * @param array the String array
+ * @param txt the String to search
+ */
+ public static void assertContains(String message, String[] array, String txt) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i].equals(txt)) {
+ return;
+ }
+ }
+ fail(formatContainsMessage(message, array, txt));
+ }
+
+ /**
+ * Checks that the given integer is contained in the given array.
+ * @param message the assert point message
+ * @param array the byte array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, byte[] array, int num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Byte[] bytes = new Byte[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Byte(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Integer(num)));
+ }
+
+ /**
+ * Checks that the given integer is contained in the given array.
+ * @param message the assert point message
+ * @param array the short array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, short[] array, int num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Short[] bytes = new Short[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Short(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Integer(num)));
+ }
+
+ /**
+ * Checks that the given integer is contained in the given array.
+ * @param message the assert point message
+ * @param array the integer array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, int[] array, int num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Integer[] bytes = new Integer[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Integer(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Integer(num)));
+ }
+
+ /**
+ * Checks that the given long is contained in the given array.
+ * @param message the assert point message
+ * @param array the long array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, long[] array, long num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Long[] bytes = new Long[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Long(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Long(num)));
+ }
+
+ /**
+ * Checks that the given float is contained in the given array.
+ * @param message the assert point message
+ * @param array the float array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, float[] array, float num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Float[] bytes = new Float[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Float(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Float(num)));
+ }
+
+ /**
+ * Checks that the given double is contained in the given array.
+ * @param message the assert point message
+ * @param array the double array
+ * @param num the number to search
+ */
+ public static void assertContains(String message, double[] array, double num) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == num) {
+ return;
+ }
+ }
+ Double[] bytes = new Double[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Double(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Double(num)));
+ }
+
+ /**
+ * Checks that the given character is contained in the given array.
+ * @param message the assert point message
+ * @param array the character array
+ * @param character the character to search
+ */
+ public static void assertContains(String message, char[] array, char character) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == character) {
+ return;
+ }
+ }
+ Character[] bytes = new Character[array.length];
+ for (int i = 0; i < array.length; i++) {
+ bytes[i] = new Character(array[i]);
+ }
+ fail(formatContainsMessage(message, bytes, new Character(character)));
+ }
+
+ /**
+ * Asserts that two doubles are equal. If they are not an
+ * AssertionFailedError is thrown with the given message.
+ * @param message the assert point message
+ * @param expected the expected double
+ * @param actual the received double
+ */
+ public static void assertEquals(String message, double expected,
+ double actual) {
+ if (expected != actual) {
+ fail(formatEqualsMessage(message, new Double(expected), new Double(
+ actual)));
+ }
+ }
+
+ /**
+ * Asserts that two objects are not equal. If they are an
+ * AssertionFailedError is thrown with the given message.
+ * @param message the assert point message
+ * @param o1 the unexpected object
+ * @param o2 the received object
+ */
+ public static void assertNotEquals(String message, Object o1, Object o2) {
+ if (o1.equals(o2)) {
+ fail(formatNotEqualsMessage(message, o1, o2));
+ }
+ }
+
+ /**
+ * Checks that the given string is contained in the given array.
+ * @param string the String to search
+ * @param array the String array
+ * @return <code>true</code> if the array contains the string
+ */
+ public static boolean contains(String string, String[] array) {
+ for (int i = 0; array != null && i < array.length; i++) {
+ if (array[i] != null && array[i].equals(string)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks that the given integer is contained in the given array.
+ * @param value the number to search
+ * @param array the integer array
+ * @return <code>true</code> if the array contains the value
+ */
+ public static boolean contains(int value, int[] array) {
+ for (int i = 0; array != null && i < array.length; i++) {
+ if (array[i] == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Formats a failure message for 'equality' tests.
+ * @param message the assertion point message
+ * @param expected the expected value
+ * @param actual the received value
+ * @return the computed message
+ */
+ private static String formatEqualsMessage(String message, Object expected,
+ Object actual) {
+ String formatted = "";
+ if (message != null) {
+ formatted = message + " ";
+ }
+ return formatted + "expected:<" + expected + "> but was:<" + actual
+ + ">";
+ }
+
+ /**
+ * Formats a failure message for 'un-equality' tests.
+ * @param message the assertion point message
+ * @param o1 the unexpected value
+ * @param o2 the received value
+ * @return the computed message
+ */
+ private static String formatNotEqualsMessage(String message, Object o1,
+ Object o2) {
+ String formatted = "";
+ if (message != null) {
+ formatted = message + " ";
+ }
+ return formatted + "o1:<" + o1 + "> is equals to o2:<" + o2 + ">";
+ }
+
+ /**
+ * Formats a failure message for 'contains' tests.
+ * @param message the assertion point message
+ * @param array the array
+ * @param txt the looked value
+ * @return the computed message
+ */
+ private static String formatContainsMessage(String message, Object[] array,
+ Object txt) {
+ String formatted = "";
+ if (message != null) {
+ formatted = message + " ";
+ }
+
+ String arr = null;
+ for (int i = 0; i < array.length; i++) {
+ if (arr == null) {
+ arr = "[" + array[i];
+ } else {
+ arr += "," + array[i];
+ }
+ }
+ arr += "]";
+
+ return formatted + "array:" + arr + " does not contains:<" + txt + ">";
+ }
+
+ /**
+ * Returns the service object of a service provided by the specified bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the specified bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public static Object getServiceObject(Bundle bundle, String itf,
+ String filter) {
+ ServiceReference ref = getServiceReference(bundle, itf, filter);
+ if (ref != null) {
+ return bundle.getBundleContext().getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services provided by the specified
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the specified bundle, offering
+ * the specified interface and matching the given filter.
+ */
+ public static Object[] getServiceObjects(Bundle bundle, String itf,
+ String filter) {
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ list[i] = bundle.getBundleContext().getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service provided by the specified
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference provided by the specified bundle, offering
+ * the specified interface and matching the given filter. If no
+ * service is found, {@code null} is returned.
+ */
+ public static ServiceReference getServiceReference(Bundle bundle,
+ String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs.length != 0) {
+ return refs[0];
+ } else {
+ // No service found
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailable(String itf) {
+ ServiceReference ref = getServiceReference(itf, null);
+ return ref != null;
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @param pid the service pid
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailableByPID(String itf, String pid) {
+ ServiceReference ref = getServiceReferenceByPID(itf, pid);
+ return ref != null;
+ }
+
+ /**
+ * Returns the service reference of the service provided by the specified
+ * bundle, offering the specified interface and having the given persistent
+ * ID.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given persistent ID.
+ */
+ public static ServiceReference getServiceReferenceByPID(Bundle bundle,
+ String itf, String pid) {
+ String filter = "(" + "service.pid" + "=" + pid + ")";
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs == null) {
+ return null;
+ } else if (refs.length == 1) {
+ return refs[0];
+ } else {
+ throw new IllegalStateException(
+ "A service lookup by PID returned several providers ("
+ + refs.length + ")" + " for " + itf + " with pid="
+ + pid);
+ }
+ }
+
+ /**
+ * Returns the service reference of all the services provided in the
+ * specified bundle, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param bundle the bundle from which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references provided in the specified bundle,
+ * offering the specified interface and matching the given filter.
+ * If no service matches, an empty array is returned.
+ */
+ public static ServiceReference[] getServiceReferences(Bundle bundle,
+ String itf, String filter) {
+ ServiceReference[] refs = null;
+ try {
+ // Get all the service references
+ refs = bundle.getBundleContext().getServiceReferences(itf, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get service references: " + e.getMessage());
+ }
+ if (refs == null) {
+ return new ServiceReference[0];
+ } else {
+ return refs;
+ }
+ }
+
+ /**
+ * Returns the service object of a service provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the local bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public Object getServiceObject(String itf, String filter) {
+ ServiceReference ref = getServiceReference(itf, filter);
+ if (ref != null) {
+ m_references.add(ref);
+ return context.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service object associated with this service reference.
+ *
+ * @param ref service reference
+ * @return the service object.
+ */
+ public Object getServiceObject(ServiceReference ref) {
+ if (ref != null) {
+ m_references.add(ref);
+ return context.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the local bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public Object[] getServiceObjects(String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(itf, filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ m_references.add(refs[i]);
+ list[i] = context.getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference provided by the local bundle, offering the
+ * specified interface and matching the given filter. If no service
+ * is found, {@code null} is returned.
+ */
+ public ServiceReference getServiceReference(String itf, String filter) {
+ return getServiceReference(context.getBundle(), itf, filter);
+ }
+
+ /**
+ * Returns the service reference of a service provided offering the
+ * specified interface.
+ *
+ * @param itf the interface provided by the searched service.
+ * @return a service reference provided by the local bundle, offering the
+ * specified interface and matching the given filter. If no service
+ * is found, {@code null} is returned.
+ */
+ public ServiceReference getServiceReference(String itf) {
+ return getServiceReference(context.getBundle(), itf, null);
+ }
+
+ /**
+ * Returns the service reference of the service provided by the local
+ * bundle, offering the specified interface and having the given persistent
+ * ID.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service provided by the local bundle, offering the specified
+ * interface and having the given persistent ID.
+ */
+ public ServiceReference getServiceReferenceByPID(String itf, String pid) {
+ return getServiceReferenceByPID(context.getBundle(), itf, pid);
+ }
+
+ /**
+ * Returns the service reference of all the services provided in the local
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references provided in the local bundle, offering
+ * the specified interface and matching the given filter. If no
+ * service matches, an empty array is returned.
+ */
+ public ServiceReference[] getServiceReferences(String itf, String filter) {
+ return getServiceReferences(context.getBundle(), itf, filter);
+ }
+
+ /**
+ * Gets the package admin exposed by the framework.
+ * Fails if the package admin is not available.
+ * @return the package admin service.
+ */
+ public PackageAdmin getPackageAdmin() {
+ PackageAdmin pa = (PackageAdmin) getServiceObject(PackageAdmin.class.getName(), null);
+ if (pa == null) {
+ fail("No package admin available");
+ }
+ return pa;
+ }
+
+ /**
+ * Refresh the packages.
+ * Fails if the package admin service is not available.
+ */
+ public void refresh() {
+ getPackageAdmin().refreshPackages(null);
+ }
+
+ /**
+ * Waits for a service. Fails on timeout.
+ * If timeout is set to 0, it sets the timeout to 10s.
+ * @param itf the service interface
+ * @param filter the filter
+ * @param timeout the timeout
+ */
+ public void waitForService(String itf, String filter, long timeout) {
+ if (timeout == 0) {
+ timeout = 10000; // Default 10 secondes.
+ }
+ ServiceReference[] refs = getServiceReferences(itf, filter);
+ long begin = System.currentTimeMillis();
+ if (refs.length != 0) {
+ return;
+ } else {
+ while(refs.length == 0) {
+ try {
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ // Interrupted
+ }
+ long now = System.currentTimeMillis();
+
+ if ((now - begin) > timeout) {
+ fail("Timeout ... no services matching with the request after " + timeout + "ms");
+ }
+ refs = getServiceReferences(itf, filter);
+ }
+ }
+ }
+
+
+ /**
+ * Installs a bundle.
+ * Fails if the bundle cannot be installed.
+ * Be aware that you have to uninstall the bundle yourself.
+ * @param url bundle url
+ * @return the installed bundle
+ */
+ public Bundle installBundle(String url) {
+ try {
+ return context.installBundle(url);
+ } catch (BundleException e) {
+ fail("Cannot install the bundle " + url + " : " + e.getMessage());
+ }
+ return null; // Can not happen
+ }
+
+ /**
+ * Installs a bundle.
+ * Fails if the bundle cannot be installed.
+ * Be aware that you have to uninstall the bundle yourself.
+ * @param url bundle url
+ * @param stream input stream containing the bundle
+ * @return the installed bundle
+ */
+ public Bundle installBundle(String url, InputStream stream) {
+ try {
+ return context.installBundle(url, stream);
+ } catch (BundleException e) {
+ fail("Cannot install the bundle " + url + " : " + e.getMessage());
+ }
+ return null; // Can not happen
+ }
+
+ /**
+ * Installs and starts a bundle.
+ * Fails if the bundle cannot be installed or an error occurs
+ * during startup. Be aware that you have to uninstall the bundle
+ * yourself.
+ * @param url the bundle url
+ * @return the Bundle object.
+ */
+ public Bundle installAndStart(String url) {
+ Bundle bundle = installBundle(url);
+ try {
+ bundle.start();
+ } catch (BundleException e) {
+ fail("Cannot start the bundle " + url + " : " + e.getMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Installs and starts a bundle.
+ * Fails if the bundle cannot be installed or an error occurs
+ * during startup. Be aware that you have to uninstall the bundle
+ * yourself.
+ * @param url the bundle url
+ * @param stream input stream containing the bundle
+ * @return the Bundle object.
+ */
+ public Bundle installAndStart(String url, InputStream stream) {
+ Bundle bundle = installBundle(url, stream);
+ try {
+ bundle.start();
+ } catch (BundleException e) {
+ fail("Cannot start the bundle " + url + " : " + e.getMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Get the bundle by its id.
+ * @param bundleId the bundle id.
+ * @return the bundle with the given id.
+ */
+ public Bundle getBundle(long bundleId) {
+ return context.getBundle(bundleId);
+ }
+
+ /**
+ * Gets a bundle by its symbolic name.
+ * Fails if no bundle matches.
+ * @param name the symbolic name of the bundle
+ * @return the bundle object.
+ */
+ public Bundle getBundle(String name) {
+ Bundle[] bundles = context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if (name.equals(bundles[i].getSymbolicName())) {
+ return bundles[i];
+ }
+ }
+ fail("No bundles with the given symbolic name " + name);
+ return null; // should not happen
+ }
+
+
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.java
new file mode 100644
index 0000000..581c14a
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.java
@@ -0,0 +1,127 @@
+/*
+ * 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.junit4osgi;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi Test Suite.
+ * Allow the injection of the bundle context.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class OSGiTestSuite extends TestSuite {
+
+ /**
+ * The bundle context of the bundle containing
+ * the test suite.
+ */
+ protected BundleContext m_context;
+
+ /**
+ * Creates a OSGiTestSuite.
+ * @param clazz the class
+ * @param bc the bundle context
+ * @see TestSuite#TestSuite(Class)
+ */
+ public OSGiTestSuite(Class clazz, BundleContext bc) {
+ super(clazz);
+ m_context = bc;
+ }
+
+ /**
+ * Creates a OSGiTestSuite.
+ * @param bc the bundle context
+ * @see TestSuite#TestSuite()
+ */
+ public OSGiTestSuite(BundleContext bc) {
+ super();
+ m_context = bc;
+ }
+
+ /**
+ * Creates a OSGiTestSuite.
+ * @param name the name
+ * @param bc the bundle context
+ * @see TestSuite#TestSuite(String)
+ */
+ public OSGiTestSuite(String name, BundleContext bc) {
+ super(name);
+ m_context = bc;
+ }
+
+ /**
+ * Creates a OSGiTestSuite.
+ * @param clazz the class
+ * @param name the name
+ * @param bc the bundle context
+ * @see TestSuite#TestSuite(Class, String)
+ */
+ public OSGiTestSuite(Class clazz, String name, BundleContext bc) {
+ super(clazz, name);
+ m_context = bc;
+ }
+
+ /**
+ * Set the bundle context.
+ * @param bc the bundle context to use.
+ */
+ public void setBundleContext(BundleContext bc) {
+ m_context = bc;
+ }
+
+ /**
+ * Adds the tests from the given class to the suite.
+ * @param testClass the class to add
+ */
+ public void addTestSuite(Class testClass) {
+ if (OSGiTestCase.class.isAssignableFrom(testClass)) {
+ addTest(new OSGiTestSuite(testClass, m_context));
+ } else if (TestCase.class.isAssignableFrom(testClass)) {
+ addTest(new TestSuite(testClass));
+ } else {
+ System.out.println("Error : the " + testClass + " is not a valid test class");
+ }
+ }
+
+ /**
+ * Executes the given {@link Test} with the
+ * given {@link TestResult}.
+ * @param test the test
+ * @param result the test result.
+ * @see junit.framework.TestSuite#runTest(junit.framework.Test, junit.framework.TestResult)
+ */
+ public void runTest(Test test, TestResult result) {
+ if (test instanceof OSGiTestSuite) {
+ ((OSGiTestSuite) test).m_context = m_context;
+ test.run(result);
+ } else if (test instanceof OSGiTestCase) {
+ ((OSGiTestCase) test).setBundleContext(m_context);
+ test.run(result);
+ } else {
+ test.run(result);
+ }
+
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/helpers/IPOJOHelper.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/helpers/IPOJOHelper.java
new file mode 100644
index 0000000..791fcfd
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/helpers/IPOJOHelper.java
@@ -0,0 +1,737 @@
+/*
+ * 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.junit4osgi.helpers;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.junit4osgi.Helper;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+/**
+ * iPOJO Helper.
+ * This helper helps getting {@link Factory}, and managing
+ * {@link ComponentInstance}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IPOJOHelper extends Helper {
+
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+ /**
+ * The test case.
+ */
+ private OSGiTestCase m_testcase;
+
+ /**
+ * List of instances.
+ */
+ private List m_instances;
+
+ /**
+ * Creates a IPOJOHelper.
+ * @param tc the OSGi Test Case
+ */
+ public IPOJOHelper(OSGiTestCase tc) {
+ super(tc);
+ m_testcase = tc;
+ m_context = m_testcase.getBundleContext();
+ m_instances = new ArrayList();
+ }
+
+ /**
+ * Disposes created instances.
+ * @see org.apache.felix.ipojo.junit4osgi.Helper#dispose()
+ */
+ public void dispose() {
+ for (int i = 0; i < m_instances.size(); i++) {
+ ((ComponentInstance) m_instances.get(i)).dispose();
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * Gets a created instance from the instance name.
+ * @param name the instance name.
+ * @return the created {@link ComponentInstance} or <code>null</code>
+ * if the instance was not created during the session.
+ */
+ public ComponentInstance getInstanceByName(String name) {
+ for (int i = 0; i < m_instances.size(); i++) {
+ if (((ComponentInstance) m_instances.get(i)).getInstanceName()
+ .equals(name)) {
+ return (ComponentInstance) m_instances.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new component instance with the given name (and empty
+ * configuration), from the factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, String instanceName) {
+
+ // Create the instance configuration
+ Properties configuration = new Properties();
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(bundle, factoryName, configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given configuration, from the
+ * factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param configuration the configuration of the component instance to
+ * create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, Dictionary configuration) {
+
+ // Retrieve the component factory.
+ Factory fact = getFactory(bundle, factoryName);
+
+ if (fact == null) {
+ // Factory not found...
+ throw new IllegalArgumentException(
+ "Cannot find the component factory (" + factoryName
+ + ") in the specified bundle ("
+ + bundle.getSymbolicName() + ").");
+ }
+
+ try {
+ return fact.createComponentInstance(configuration);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Cannot create the component instance with the given configuration:"
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, String instanceName, Dictionary configuration) {
+
+ // Add the instance name to the configuration
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(bundle, factoryName, configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name (and an empty
+ * configuration), from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ String instanceName) {
+
+ // Create the instance configuration
+ Properties configuration = new Properties();
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(serviceContext, factoryName,
+ configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ Dictionary configuration) {
+
+ // Retrieve the component factory.
+ Factory fact = getFactory(serviceContext, factoryName);
+
+ if (fact == null) {
+ // Factory not found...
+ throw new IllegalArgumentException(
+ "Cannot find the component factory (" + factoryName
+ + ") in the specified service context.");
+ }
+
+ try {
+ return fact.createComponentInstance(configuration);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Cannot create the component instance with the given configuration: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ String instanceName, Dictionary configuration) {
+
+ // Add the instance name to the configuration
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(serviceContext, factoryName,
+ configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name (and empty
+ * configuration), from the factory specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, defined in the
+ * local bundle.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ String instanceName) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, instanceName);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with the given configuration, from the
+ * factory specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, in the local
+ * bundle.
+ * @param configuration the configuration of the component instance to
+ * create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ Dictionary configuration) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, configuration);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with no configuration, from the factory
+ * specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, in the local
+ * bundle.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, (Dictionary) null);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given bundle.
+ *
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ String instanceName, Dictionary configuration) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, instanceName, configuration);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Returns the component factory with the given name in the local bundle.
+ *
+ * @param factoryName the name of the factory to retrieve.
+ * @return the component factory with the given name in the local bundle, or
+ * {@code null} if not found.
+ */
+ public Factory getFactory(String factoryName) {
+ return getFactory(m_context.getBundle(), factoryName);
+ }
+
+ /**
+ * Returns the handler factory with the given name in the local bundle.
+ *
+ * @param factoryName the name of the handler factory to retrieve.
+ * @return the handler factory with the given name in the local bundle, or
+ * {@code null} if not found.
+ */
+ public HandlerFactory getHandlerFactory(String factoryName) {
+ return getHandlerFactory(m_context.getBundle(), factoryName);
+ }
+
+ /**
+ * Returns the metadata description of the component defined in this bundle.
+ *
+ * @param component the name of the locally defined component.
+ * @return the metadata description of the component with the given name,
+ * defined in this given bundle, or {@code null} if not found.
+ */
+ public Element getMetadata(String component) {
+ return getMetadata(m_context.getBundle(), component);
+ }
+
+ /**
+ * Returns the component factory with the given name in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the defined factory.
+ * @return the component factory with the given name in the given bundle, or
+ * {@code null} if not found.
+ */
+ public static Factory getFactory(Bundle bundle, String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the component factories services in the bundle.
+ refs = bundle.getBundleContext().getServiceReferences(
+ Factory.class.getName(),
+ "(factory.name=" + factoryName + ")");
+ if (refs != null) {
+ return (Factory) bundle.getBundleContext().getService(refs[0]);
+ }
+
+ // Factory not found...
+ return null;
+
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get the component factory services: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the component factory with the given name, registered in the
+ * given service context.
+ *
+ * @param serviceContext the service context in which the factory service is
+ * defined.
+ * @param factoryName the name of the factory.
+ * @return the component factory with the given name, registered in the
+ * given service context.
+ */
+ public static Factory getFactory(ServiceContext serviceContext,
+ String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the component factories services in the service
+ // context.
+ refs = serviceContext.getServiceReferences(Factory.class.getName(),
+ "(factory.name=" + factoryName + ")");
+ if (refs != null) {
+ return (Factory) serviceContext.getService(refs[0]);
+ }
+ return null;
+
+ } catch (InvalidSyntaxException e) {
+ System.err.println("Cannot get the factory " + factoryName + " : "
+ + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Returns the handler factory with the given name in the given bundle.
+ *
+ * @param bundle the bundle from which the handler factory is defined.
+ * @param factoryName the name of the handler factory to retrieve.
+ * @return the handler factory with the given name in the given bundle, or
+ * {@code null} if not found.
+ */
+ public static HandlerFactory getHandlerFactory(Bundle bundle,
+ String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the handler factories services in the bundle.
+ refs = bundle.getBundleContext().getServiceReferences(
+ HandlerFactory.class.getName(),
+ "(" + Handler.HANDLER_NAME_PROPERTY + "=" + factoryName
+ + ")");
+ if (refs != null) {
+ return (HandlerFactory) bundle.getBundleContext().getService(
+ refs[0]);
+ }
+
+ // Factory not found...
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get the handler factory services: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the metadata description of the component with the given name,
+ * defined in the given bundle.
+ *
+ * @param bundle the bundle from which the component is defined.
+ * @param component the name of the defined component.
+ * @return the metadata description of the component with the given name,
+ * defined in the given bundle, or {@code null} if not found.
+ */
+ public static Element getMetadata(Bundle bundle, String component) {
+
+ // Retrieves the component description from the bundle's manifest.
+ String elem = (String) bundle.getHeaders().get("iPOJO-Components");
+ if (elem == null) {
+ throw new IllegalArgumentException(
+ "Cannot find iPOJO-Components descriptor in the specified bundle ("
+ + bundle.getSymbolicName()
+ + "). Not an iPOJO bundle.");
+ }
+
+ // Parses the retrieved description and find the component with the
+ // given name.
+ try {
+ Element element = ManifestMetadataParser.parseHeaderMetadata(elem);
+ Element[] childs = element.getElements("component");
+ for (int i = 0; i < childs.length; i++) {
+ String name = childs[i].getAttribute("name");
+ String clazz = childs[i].getAttribute("classname");
+ if (name != null && name.equalsIgnoreCase(component)) {
+ return childs[i];
+ }
+ if (clazz.equalsIgnoreCase(component)) {
+ return childs[i];
+ }
+ }
+
+ // Component not found...
+ return null;
+
+ } catch (ParseException e) {
+ throw new IllegalStateException(
+ "Cannot parse the components from specified bundle ("
+ + bundle.getSymbolicName() + "): " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the service object of a service registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which the service is
+ * searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the specified bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public static Object getServiceObject(ServiceContext serviceContext,
+ String itf, String filter) {
+ ServiceReference ref = getServiceReference(serviceContext, itf, filter);
+ if (ref != null) {
+ return serviceContext.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the specified bundle, offering
+ * the specified interface and matching the given filter.
+ */
+ public static Object[] getServiceObjects(ServiceContext serviceContext,
+ String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ list[i] = serviceContext.getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference registered in the specified service context,
+ * offering the specified interface and matching the given filter.
+ * If no service is found, {@code null} is returned.
+ */
+ public static ServiceReference getServiceReference(
+ ServiceContext serviceContext, String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs.length != 0) {
+ return refs[0];
+ } else {
+ // No service found
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service reference of the service registered in the specified
+ * service context, offering the specified interface and having the given
+ * persistent ID.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service registered in the specified service context, offering
+ * the specified interface and having the given persistent ID.
+ */
+ public static ServiceReference getServiceReferenceByPID(
+ ServiceContext serviceContext, String itf, String pid) {
+ String filter = "(" + "service.pid" + "=" + pid + ")";
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs == null) {
+ return null;
+ } else if (refs.length == 1) {
+ return refs[0];
+ } else {
+ throw new IllegalStateException(
+ "A service lookup by PID returned several providers ("
+ + refs.length + ")" + " for " + itf + " with pid="
+ + pid);
+ }
+ }
+
+ /**
+ * Returns the service reference of all the services registered in the
+ * specified service context, offering the specified interface and matching
+ * the given filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references registered in the specified service
+ * context, offering the specified interface and matching the given
+ * filter. If no service matches, an empty array is returned.
+ */
+ public static ServiceReference[] getServiceReferences(
+ ServiceContext serviceContext, String itf, String filter) {
+ ServiceReference[] refs = null;
+ try {
+ // Get all the service references
+ refs = serviceContext.getServiceReferences(itf, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get service references: " + e.getMessage());
+ }
+ if (refs == null) {
+ return new ServiceReference[0];
+ } else {
+ return refs;
+ }
+ }
+
+ /**
+ * Returns the service reference of a service registered in the specified
+ * service context, offering the specified interface and having the given
+ * name.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service registered in the specified service context, offering
+ * the specified interface and having the given name.
+ */
+ public static ServiceReference getServiceReferenceByName(
+ ServiceContext serviceContext, String itf, String name) {
+ String filter = null;
+ if (itf.equals(Factory.class.getName())
+ || itf.equals(ManagedServiceFactory.class.getName())) {
+ filter = "(" + "factory.name" + "=" + name + ")";
+ } else if (itf.equals(Architecture.class.getName())) {
+ filter = "(" + "architecture.instance" + "=" + name + ")";
+ } else {
+ filter = "(" + "instance.name" + "=" + name + ")";
+ }
+ return getServiceReference(serviceContext, itf, filter);
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailable(ServiceContext sc, String itf) {
+ ServiceReference ref = getServiceReference(sc, itf, null);
+ return ref != null;
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @param name the service provider name
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailableByName(ServiceContext sc,
+ String itf, String name) {
+ ServiceReference ref = getServiceReferenceByName(sc, itf, name);
+ return ref != null;
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @param pid the pid of the service
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailableByPID(ServiceContext sc,
+ String itf, String pid) {
+ ServiceReference ref = getServiceReferenceByPID(sc, itf, pid);
+ return ref != null;
+ }
+
+ /**
+ * Returns the service reference of a service provided by the specified
+ * bundle, offering the specified interface and having the given name.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given name.
+ */
+ public static ServiceReference getServiceReferenceByName(Bundle bundle,
+ String itf, String name) {
+ String filter = null;
+ if (itf.equals(Factory.class.getName())
+ || itf.equals(ManagedServiceFactory.class.getName())) {
+ filter = "(" + "factory.name" + "=" + name + ")";
+ } else if (itf.equals(Architecture.class.getName())) {
+ filter = "(" + "architecture.instance" + "=" + name + ")";
+ } else {
+ filter = "(" + "instance.name" + "=" + name + ")";
+ }
+ return OSGiTestCase.getServiceReference(bundle, itf, filter);
+ }
+
+ /**
+ * Returns the service reference of a service provided by the local bundle,
+ * offering the specified interface and having the given name.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given name.
+ */
+ public ServiceReference getServiceReferenceByName(String itf, String name) {
+ return getServiceReferenceByName(m_context.getBundle(), itf, name);
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @param name the service provider name
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailableByName(String itf, String name) {
+ ServiceReference ref = getServiceReferenceByName(itf, name);
+ return ref != null;
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.java
new file mode 100644
index 0000000..45c928e
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.java
@@ -0,0 +1,399 @@
+/*
+ * 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.junit4osgi.impl;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestSuite;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Detect test suite from installed bundles.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JunitExtender implements OSGiJunitRunner {
+
+ /**
+ * Suite method name.
+ */
+ public static final String SUITE_METHODNAME = "suite";
+
+ /**
+ * List of found suites (Bundle-> List of Class).
+ */
+ private Map/*<Bundle, List<Class>>*/ m_suites = new HashMap/*<Bundle, List<Class>>*/();
+
+ /**
+ * The result printer.
+ * By default, prints result on {@link System#out}
+ */
+ private ResultPrinter m_printer = new ResultPrinter(System.out);
+
+ /**
+ * The log service used to log messages.
+ * If not provided, a default implementation
+ * printing messages on the console is used.
+ */
+ private LogService m_log;
+
+ /**
+ * A new matching bundle arrives.
+ * @param bundle the matching bundle
+ * @param header the looked header value
+ */
+ void onBundleArrival(Bundle bundle, String header) {
+ String[] tss = ParseUtils.split(header, ",");
+ for (int i = 0; i < tss.length; i++) {
+ try {
+ if (tss[i].length() != 0) {
+ m_log.log(LogService.LOG_INFO, "Loading " + tss[i]);
+ Class/*<? extends Test>*/ clazz = bundle.loadClass(tss[i].trim());
+ addTestSuite(bundle, clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ m_log.log(LogService.LOG_ERROR, "The test suite " + tss[i] + " is not in the bundle " + bundle.getBundleId() + " : " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Adds a test suite.
+ * @param bundle the bundle declaring the test suite.
+ * @param test the test class.
+ */
+ private synchronized void addTestSuite(Bundle bundle, Class/*<? extends Test>*/ test) {
+ List/*<Class>*/ list = (List) m_suites.get(bundle);
+ if (list == null) {
+ list = new ArrayList/*<Class>*/();
+ list.add(test);
+ m_suites.put(bundle, list);
+ } else {
+ list.add(test);
+ }
+ }
+
+ /**
+ * Removes the test suites provided by the given bundles.
+ * @param bundle the leaving bundles.
+ */
+ private synchronized void removeTestSuites(Bundle bundle) {
+ List list = (List) m_suites.remove(bundle);
+ m_log.log(LogService.LOG_INFO, "Unload test suites " + list);
+ }
+
+ /**
+ * A matching bundle is leaving.
+ * @param bundle the leaving bundle.
+ */
+ void onBundleDeparture(Bundle bundle) {
+ removeTestSuites(bundle);
+ }
+
+ /**
+ * Set the result printer.
+ * @param pw the stream to use.
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#setResultPrinter(java.io.PrintStream)
+ */
+ public void setResultPrinter(PrintStream pw) {
+ m_printer = new ResultPrinter(pw);
+ }
+
+ /**
+ * Runs tests.
+ * @return the list of {@link TestResult}
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#run()
+ */
+ public synchronized List/*<TestResult>*/ run() {
+ List/*<TestResult>*/ results = new ArrayList/*<TestResult>*/(m_suites.size());
+ Iterator/*<Entry<Bundle, List<Class>>>*/ it = m_suites.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry/*<Bundle, List<Class>>*/ entry = (Entry) it.next();
+ Bundle bundle = (Bundle) entry.getKey();
+ List/*<Class>*/ list = (List) m_suites.get(bundle);
+ for (int i = 0; i < list.size(); i++) {
+ Test test = createTestFromClass((Class) list.get(i), bundle);
+ TestResult tr = doRun(test);
+ results.add(tr);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Internal methods executing tests.
+ * @param test the test to execute
+ * @return the result
+ */
+ private TestResult doRun(Test test) {
+ TestResult result = new TestResult();
+ result.addListener(m_printer);
+ long startTime = System.currentTimeMillis();
+
+ test.run(result);
+
+ long endTime = System.currentTimeMillis();
+ long runTime = endTime - startTime;
+ m_printer.print(result, runTime);
+
+ return result;
+ }
+
+ /**
+ * Creates a {@link Test} object from the
+ * given class from the given bundle.
+ * This method creates {@link OSGiTestCase} and
+ * {@link OSGiTestSuite} when required.
+ * @param clazz the class
+ * @param bundle the bundle
+ * @return the resulting Test object.
+ */
+ private Test createTestFromClass(Class/*<?>*/ clazz, Bundle bundle) {
+ Method suiteMethod = null;
+ boolean bc = false;
+ try {
+ suiteMethod = clazz.getMethod(SUITE_METHODNAME, new Class[0]);
+ } catch (Exception e) {
+ // try to use a suite method receiving a bundle context
+ try {
+ suiteMethod = clazz.getMethod(SUITE_METHODNAME, new Class[] { BundleContext.class });
+ bc = true;
+ } catch (Exception e2) {
+ // try to extract a test suite automatically
+ if (OSGiTestSuite.class.isAssignableFrom(clazz)) {
+ OSGiTestSuite ts = new OSGiTestSuite(clazz, getBundleContext(bundle));
+ return ts;
+ } else if (OSGiTestCase.class.isAssignableFrom(clazz)) {
+ OSGiTestSuite ts = new OSGiTestSuite(clazz, getBundleContext(bundle));
+ return ts;
+ } else {
+ return new TestSuite(clazz);
+ }
+ }
+ }
+
+ if (!Modifier.isStatic(suiteMethod.getModifiers())) {
+ m_log.log(LogService.LOG_ERROR, "Suite() method must be static");
+ return null;
+ }
+ Test test = null;
+ try {
+ if (bc) {
+ test = (Test) suiteMethod.invoke(null, new Object[] { getBundleContext(bundle) }); // static method injection the bundle context
+ } else {
+ test = (Test) suiteMethod.invoke(null, (Object[]) new Class[0]); // static method
+ }
+ } catch (InvocationTargetException e) {
+ m_log.log(LogService.LOG_ERROR, "Failed to invoke suite():" + e.getTargetException().toString());
+ return null;
+ } catch (IllegalAccessException e) {
+ m_log.log(LogService.LOG_ERROR, "Failed to invoke suite():" + e.toString());
+ return null;
+ }
+
+ return test;
+ }
+
+ /**
+ * Gets the list of {@link Test}.
+ * @return the list of {@link Test}
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#getTests()
+ */
+ public synchronized List/*<Test>*/ getTests() {
+ List/*<Test>*/ results = new ArrayList/*<Test>*/();
+ Iterator/*<Entry<Bundle, List<Class>>>*/ it = m_suites.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry/*<Bundle, List<Class>>*/ entry = (Entry) it.next();
+ Bundle bundle = (Bundle) entry.getKey();
+ List/*<Class>*/ list = (List) m_suites.get(bundle);
+ for (int i = 0; i < list.size(); i++) {
+ Test test = createTestFromClass((Class) list.get(i), bundle);
+ results.add(test);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Runs the given tests.
+ * @param test the test to execute
+ * @return the result
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#run(junit.framework.Test)
+ */
+ public TestResult run(Test test) {
+ return doRun(test);
+ }
+
+ /**
+ * Gets the list of {@link Test} from the bundle (specified
+ * by using the bundle id).
+ * @param bundleId the bundle id
+ * @return the list of {@link Test} declared in this bundle.
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#getTests(long)
+ */
+ public synchronized List/*<Test>*/ getTests(long bundleId) {
+ Iterator/*<Entry<Bundle, List<Class>>>*/ it = m_suites.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry/*<Bundle, List<Class>>*/ entry = (Entry) it.next();
+ Bundle bundle = (Bundle) entry.getKey();
+ if (bundle.getBundleId() == bundleId) {
+ List/*<Test>*/ results = new ArrayList/*<Test>*/();
+ List/*<Class>*/ list = (List) m_suites.get(bundle);
+ for (int i = 0; i < list.size(); i++) {
+ Test test = createTestFromClass((Class) list.get(i), bundle);
+ results.add(test);
+ }
+ return results;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Runs the tests declared in the bundle
+ * (specified by the bundle id).
+ * @param bundleId the bundle id
+ * @return the List of {@link TestResult}
+ * @see org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner#run(long)
+ */
+ public synchronized List/*<TestResult>*/ run(long bundleId) {
+ Iterator/*<Entry<Bundle, List<Class>>>*/ it = m_suites.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry/*<Bundle, List<Class>>*/ entry = (Entry) it.next();
+ Bundle bundle = (Bundle) entry.getKey();
+ if (bundle.getBundleId() == bundleId) {
+ List/*<TestResult>*/ results = new ArrayList/*<TestResult>*/();
+ List/*<Class>*/ list = (List) m_suites.get(bundle);
+ for (int i = 0; i < list.size(); i++) {
+ Test test = createTestFromClass((Class) list.get(i), bundle);
+ TestResult tr = doRun(test);
+ results.add(tr);
+ }
+ return results;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Stop method.
+ * Clears test suites.
+ */
+ public synchronized void stopping() {
+ m_log.log(LogService.LOG_INFO, "Cleaning test suites ...");
+ m_suites.clear();
+ }
+
+ /**
+ * Start method.
+ */
+ public void starting() {
+ m_log.log(LogService.LOG_INFO, "Junit Extender starting ...");
+ }
+
+ /**
+ * Helper method analyzing the {@link Bundle} object
+ * to get the {@link BundleContext} object.
+ * @param bundle the Bundle
+ * @return the BundleContext of <code>null</code> if
+ * the BundleContext cannot be collected.
+ */
+ private BundleContext getBundleContext(Bundle bundle) {
+ if (bundle == null) { return null; }
+
+ // getBundleContext (OSGi 4.1)
+ Method meth = null;
+ try {
+ meth = bundle.getClass().getMethod("getBundleContext", new Class[0]);
+ } catch (SecurityException e) {
+ // Nothing do to, will try the Equinox method
+ } catch (NoSuchMethodException e) {
+ // Nothing do to, will try the Equinox method
+ }
+
+ // try Equinox getContext if not found.
+ if (meth == null) {
+ try {
+ meth = bundle.getClass().getMethod("getContext", new Class[0]);
+ } catch (SecurityException e) {
+ // Nothing do to, will try field inspection
+ } catch (NoSuchMethodException e) {
+ // Nothing do to, will try field inspection
+ }
+ }
+
+ if (meth != null) {
+ if (! meth.isAccessible()) {
+ meth.setAccessible(true);
+ }
+ try {
+ return (BundleContext) meth.invoke(bundle, new Object[0]);
+ } catch (IllegalArgumentException e) {
+ m_log.log(LogService.LOG_ERROR, "Cannot get the BundleContext by invoking " + meth.getName(), e);
+ return null;
+ } catch (IllegalAccessException e) {
+ m_log.log(LogService.LOG_ERROR, "Cannot get the BundleContext by invoking " + meth.getName(), e);
+ return null;
+ } catch (InvocationTargetException e) {
+ m_log.log(LogService.LOG_ERROR, "Cannot get the BundleContext by invoking " + meth.getName(), e);
+ return null;
+ }
+ }
+
+ // Else : Field inspection (KF and Prosyst)
+ Field[] fields = bundle.getClass().getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ if (BundleContext.class.isAssignableFrom(fields[i].getType())) {
+ if (! fields[i].isAccessible()) {
+ fields[i].setAccessible(true);
+ }
+ try {
+ return (BundleContext) fields[i].get(bundle);
+ } catch (IllegalArgumentException e) {
+ m_log.log(LogService.LOG_ERROR, "Cannot get the BundleContext by reflecting on " + fields[i].getName(), e);
+ return null;
+ } catch (IllegalAccessException e) {
+ m_log.log(LogService.LOG_ERROR, "Cannot get the BundleContext by reflecting on " + fields[i].getName(), e);
+ return null;
+ }
+ }
+ }
+ m_log.log(LogService.LOG_ERROR, "Cannot find the BundleContext for " + bundle.getSymbolicName(), null);
+ return null;
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/LogServiceImpl.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/LogServiceImpl.java
new file mode 100644
index 0000000..71afd82
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/LogServiceImpl.java
@@ -0,0 +1,107 @@
+/*
+ * 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.junit4osgi.impl;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * Log Service default implementation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LogServiceImpl implements LogService {
+
+ /**
+ * Creates a message.
+ * @param level the log level
+ * @param msg the message
+ * @param exception the thrown exception
+ * @return the computed message
+ */
+ private String computeLogMessage(int level, String msg, Throwable exception) {
+ String message = null;
+ switch (level) {
+ case LogService.LOG_DEBUG:
+ message = "[DEBUG] " + msg;
+ break;
+ case LogService.LOG_ERROR:
+ message = "[ERROR] " + msg;
+ break;
+ case LogService.LOG_INFO:
+ message = "[INFO] " + msg;
+ break;
+ case LogService.LOG_WARNING:
+ message = "[WARNING] " + msg;
+ break;
+ default:
+ break;
+ }
+
+ if (exception != null) {
+ message = message + " : " + exception.getMessage();
+ }
+
+ return message;
+ }
+
+ /**
+ * Logs a message.
+ * @param arg0 the log level
+ * @param arg1 the message
+ * @see org.osgi.service.log.LogService#log(int, java.lang.String)
+ */
+ public void log(int arg0, String arg1) {
+ System.err.println(computeLogMessage(arg0, arg1, null));
+ }
+
+ /**
+ * Logs a message.
+ * @param arg0 the log level
+ * @param arg1 the message
+ * @param arg2 the thrown exception
+ * @see org.osgi.service.log.LogService#log(int, java.lang.String)
+ */
+ public void log(int arg0, String arg1, Throwable arg2) {
+ System.err.println(computeLogMessage(arg0, arg1, arg2));
+ }
+
+ /**
+ * Logs a message.
+ * @param arg0 the service reference
+ * @param arg1 the log level
+ * @param arg2 the message
+ * @see org.osgi.service.log.LogService#log(ServiceReference, int, String)
+ */
+ public void log(ServiceReference arg0, int arg1, String arg2) {
+ System.err.println(computeLogMessage(arg1, arg2, null));
+ }
+
+ /**
+ * Logs a message.
+ * @param arg0 the service reference
+ * @param arg1 the log level
+ * @param arg2 the message
+ * @param arg3 the thrown exception
+ * @see org.osgi.service.log.LogService#log(ServiceReference, int, String, Throwable)
+ */
+ public void log(ServiceReference arg0, int arg1, String arg2, Throwable arg3) {
+ System.err.println(computeLogMessage(arg1, arg2, arg3));
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.java
new file mode 100644
index 0000000..906658b
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.java
@@ -0,0 +1,227 @@
+/*
+ * 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.junit4osgi.impl;
+
+import java.io.PrintStream;
+import java.text.NumberFormat;
+import java.util.Enumeration;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.runner.BaseTestRunner;
+
+/**
+ * Result Printer.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResultPrinter implements TestListener {
+ /**
+ * the writer.
+ */
+ PrintStream m_fWriter;
+
+ /**
+ * The column .
+ */
+ int m_fColumn = 0;
+
+ /**
+ * Creates a ResultPrinter.
+ * @param writer the printer
+ */
+ public ResultPrinter(PrintStream writer) {
+ m_fWriter = writer;
+ }
+
+ /**
+ * Prints the result.
+ * @param result the test result
+ * @param runTime the test duration
+ */
+ synchronized void print(TestResult result, long runTime) {
+ printHeader(runTime);
+ printErrors(result);
+ printFailures(result);
+ printFooter(result);
+ }
+
+ /**
+ * Prints message wiating for prompt.
+ */
+ void printWaitPrompt() {
+ getWriter().println();
+ getWriter().println("<RETURN> to continue");
+ }
+
+ /*
+ * Internal methods
+ */
+
+ /**
+ * Prints the result header.
+ * @param runTime the test execution duration
+ */
+ protected void printHeader(long runTime) {
+ getWriter().println();
+ getWriter().println("Time: " + elapsedTimeAsString(runTime));
+ }
+
+ /**
+ * Prints the errors.
+ * @param result the test result
+ */
+ protected void printErrors(TestResult result) {
+ printDefects(result.errors(), result.errorCount(), "error");
+ }
+
+ /**
+ * Prints failures.
+ * @param result the test result
+ */
+ protected void printFailures(TestResult result) {
+ printDefects(result.failures(), result.failureCount(), "failure");
+ }
+
+ /**
+ * Prints failures.
+ * @param booBoos the failures
+ * @param count the number of failures
+ * @param type the type
+ */
+ protected void printDefects(Enumeration/*<TestFailure>*/ booBoos, int count, String type) {
+ if (count == 0) {
+ return;
+ }
+
+ if (count == 1) {
+ getWriter().println("There was " + count + " " + type + ":");
+ } else {
+ getWriter().println("There were " + count + " " + type + "s:");
+ }
+
+ for (int i = 1; booBoos.hasMoreElements(); i++) {
+ printDefect((TestFailure) booBoos.nextElement(), i);
+ }
+ }
+
+ /**
+ * Prints a failure.
+ * @param booBoo the failure
+ * @param count the count
+ */
+ public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+ printDefectHeader(booBoo, count);
+ printDefectTrace(booBoo);
+ }
+
+ /**
+ * Prints defect header.
+ * @param booBoo the failure
+ * @param count the count
+ */
+ protected void printDefectHeader(TestFailure booBoo, int count) {
+ // I feel like making this a println, then adding a line giving the throwable a chance to print something
+ // before we get to the stack trace.
+ getWriter().print(count + ") " + booBoo.failedTest());
+ }
+
+ /**
+ * Prints the stack trace.
+ * @param booBoo the failure
+ */
+ protected void printDefectTrace(TestFailure booBoo) {
+ getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+ }
+
+ /**
+ * Prints the footer.
+ * @param result the test result.
+ */
+ protected void printFooter(TestResult result) {
+ if (result.wasSuccessful()) {
+ getWriter().println();
+ getWriter().print("OK");
+ getWriter().println(" (" + result.runCount() + " test" + (result.runCount() == 1 ? "" : "s") + ")");
+
+ } else {
+ getWriter().println();
+ getWriter().println("FAILURES!!!");
+ getWriter().println("Tests run: " + result.runCount() + ", Failures: " + result.failureCount() + ", Errors: " + result.errorCount());
+ }
+ getWriter().println();
+ }
+
+ /**
+ * Returns the formatted string of the elapsed time.
+ * @param runTime the elapsed time
+ * @return the elapsed time.
+ */
+ protected String elapsedTimeAsString(long runTime) {
+ return NumberFormat.getInstance().format((double) runTime / 1000);
+ }
+
+ public PrintStream getWriter() {
+ return m_fWriter;
+ }
+
+ /**
+ * Adds an error.
+ * @param test the test in error.
+ * @param t the thrown error
+ * @see junit.framework.TestListener#addError(Test, Throwable)
+ */
+ public void addError(Test test, Throwable t) {
+ getWriter().print("E");
+ }
+
+ /**
+ * Adds a failure.
+ * @param test the failing test.
+ * @param t the thrown failure
+ * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+ */
+ public void addFailure(Test test, AssertionFailedError t) {
+ getWriter().print("F");
+ }
+
+ /**
+ * A test ends.
+ * (do nothing)
+ * @param test the ending test
+ * @see junit.framework.TestListener#endTest(Test)
+ */
+ public void endTest(Test test) { }
+
+ /**
+ * A test starts.
+ * @param test the starting test
+ * @see junit.framework.TestListener#startTest(Test)
+ */
+ public void startTest(Test test) {
+ getWriter().print(".");
+ if (m_fColumn++ >= 40) {
+ getWriter().println();
+ m_fColumn = 0;
+ }
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.java
new file mode 100644
index 0000000..9d59e00
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.java
@@ -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.junit4osgi.test;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+
+/**
+ * Simple OSGi Test Case.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestOSGiTestCase extends OSGiTestCase {
+
+ /**
+ * Test.
+ */
+ public void test1() {
+ System.out.println("Test BC");
+ assertNotNull("Test bundle context", getContext());
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.java
new file mode 100644
index 0000000..746a017
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.java
@@ -0,0 +1,48 @@
+/*
+ * 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.junit4osgi.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiTestSuite;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Simple OSGi Test suite.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestOSGiTestSuite extends TestSuite {
+
+ /**
+ * Suite method.
+ * @param bc the bundle context
+ * @return the Test Suite.
+ */
+ public static Test suite(BundleContext bc) {
+ TestSuite ts = new TestSuite();
+ ts.setName("Test OSGi suite() method");
+ ts.addTestSuite(TestTestCase.class);
+ OSGiTestSuite ots = new OSGiTestSuite(TestOSGiTestCase.class, bc);
+ ots.setBundleContext(bc);
+ ts.addTest(ots);
+ return ts;
+ }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.java
new file mode 100644
index 0000000..c2f0ae4
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.java
@@ -0,0 +1,49 @@
+/*
+ * 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.junit4osgi.test;
+
+import junit.framework.TestCase;
+
+/**
+ * Simple Test Case.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestTestCase extends TestCase {
+
+ /**
+ * test1.
+ */
+ public void test1() { }
+
+ /**
+ * test2.
+ */
+ public void test2() { }
+
+ /**
+ * test3.
+ */
+ public void test3() { }
+
+ /**
+ * test4.
+ */
+ public void test4() { }
+
+}
diff --git a/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.java b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.java
new file mode 100644
index 0000000..d559ed9
--- /dev/null
+++ b/ipojo/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.java
@@ -0,0 +1,41 @@
+/*
+ * 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.junit4osgi.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Simple OSGi Test Suite.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestTestSuite extends TestSuite {
+
+ /**
+ * Suite method.
+ * @return the test suite.
+ */
+ public static Test suite() {
+ TestSuite ts = new TestSuite();
+ ts.setName("Test suite() method");
+ ts.addTestSuite(TestTestCase.class);
+ return ts;
+ }
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/LICENSE b/ipojo/junit4osgi/maven-junit4osgi-plugin/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/NOTICE b/ipojo/junit4osgi/maven-junit4osgi-plugin/NOTICE
new file mode 100644
index 0000000..657444e
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/NOTICE
@@ -0,0 +1,31 @@
+Apache Felix iPOJO junit4osgi Maven Plugin
+Copyright 2008-2009 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+This product uses software developed by
+Junit project (http://junit.org)
+Licensed under Common Public License 1.0.
+
+This product uses software developed at
+The Codehaus (http://www.codehaus.org)
+Licensed under the Apache License 2.0.
+
+III. License Summary
+- Apache License 2.0
+- Common Public License 1.0
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/doc/changelog.txt b/ipojo/junit4osgi/maven-junit4osgi-plugin/doc/changelog.txt
new file mode 100644
index 0000000..524e88b
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/doc/changelog.txt
@@ -0,0 +1,3 @@
+Version 1.0.0
+-------------
+ * Initial release
\ No newline at end of file
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/pom.xml b/ipojo/junit4osgi/maven-junit4osgi-plugin/pom.xml
new file mode 100644
index 0000000..785248c
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/pom.xml
@@ -0,0 +1,113 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>maven-junit4osgi-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+ <version>1.1.0-SNAPSHOT</version>
+ <name>Junit4OSGi Maven Plugin</name>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.0.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-model</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.extender</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.cobertura</groupId>
+ <artifactId>cobertura</artifactId>
+ <version>1.9</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Installer.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Installer.java
new file mode 100644
index 0000000..3519403
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Installer.java
@@ -0,0 +1,207 @@
+/*
+ * 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.junit4osgi.plugin;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+import java.util.jar.JarFile;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.project.MavenProject;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+/**
+ * Bundle Activator installing bundles in the embedded OSGi.
+ * Installed bundles are the junit4osgi framework, the required bundle and the artifact bundle (if enable).
+ * Bundles are installed from the local maven repository.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Installer implements BundleActivator {
+
+ /**
+ * The list of artifact containing bundles for the junit4osgi framework.
+ */
+ private List m_artifacts;
+
+ /**
+ * The current maven project.
+ */
+ private MavenProject m_project;
+
+ /**
+ * Flag enabling/disabling the deployment of the current
+ * project artifact.
+ */
+ private boolean m_deployCurrent;
+
+ /**
+ * List of bundle URLs to install.
+ */
+ private List m_bundles;
+
+
+ /**
+ * Creates a Installer.
+ * @param artifacts the list of artifact containing bundles for the junit4osgi framework.
+ * @param bundles the list of bundle URLs to install
+ * @param project the current maven project
+ * @param deployCurrentArtifact flag enabling/disabling the deployment of the current project artifact
+ */
+ public Installer(List artifacts, List bundles, MavenProject project, boolean deployCurrentArtifact) {
+ this.m_artifacts = artifacts;
+ this.m_project = project;
+ m_deployCurrent = deployCurrentArtifact;
+ this.m_bundles = bundles;
+ }
+
+ /**
+ * Installs and starts the iPOJO bundle.
+ * @param context the bundle context.
+ * @throws BundleException when the bundle cannot be installed or started correctly
+ */
+ private void installIPOJO(BundleContext context) throws BundleException {
+ String path = getUrlByArtifactId("org.apache.felix.ipojo").toString();
+ Bundle bundle = context.installBundle(path);
+ bundle.start();
+ }
+
+ /**
+ * Installs and starts the Junit4OSGi bundle.
+ * @param context the bundle context.
+ * @throws BundleException when the bundle cannot be installed or started correctly
+ */
+ private void installJunit(BundleContext context) throws BundleException {
+ String path = getUrlByArtifactId("org.apache.felix.ipojo.junit4osgi").toString();
+ Bundle bundle = context.installBundle(path);
+ bundle.start();
+ }
+
+ /**
+ * Installs and starts the iPOJO Extender Handler bundle.
+ * @param context the bundle context.
+ * @throws BundleException when the bundle cannot be installed or started correctly
+ */
+ private void installExtender(BundleContext context) throws BundleException {
+ String path = getUrlByArtifactId("org.apache.felix.ipojo.handler.extender").toString();
+ Bundle bundle = context.installBundle(path);
+ bundle.start();
+ }
+
+ /**
+ * Installs and Starts required bundles.
+ * @param context the bundle context used to deploy bundles.
+ * @throws BundleException when a bundle cannot be installed or started correctly
+ */
+ private void deployBundles(BundleContext context) throws BundleException {
+ for (int i = 0; i < m_bundles.size(); i++) {
+ URL url = (URL) m_bundles.get(i);
+ Bundle bundle = context.installBundle(url.toString());
+ bundle.start();
+ }
+ }
+
+ /**
+ * Gets the bundle URL from the artifact list.
+ * @param id the dependency id.
+ * @return the bundle URL or <code>null</code> if the URL cannot
+ * be found.
+ */
+ private URL getUrlByArtifactId(String id) {
+ for (int i = 0; i < m_artifacts.size(); i++) {
+ Artifact artifact = (Artifact) m_artifacts.get(i);
+ if (artifact.getArtifactId().equals(id)) {
+ try {
+ return artifact.getFile().toURL();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Deploys the current bundle if enable.
+ * @param context the bundle context
+ * @throws BundleException when the bundle cannot be installed or started correctly.
+ */
+ private void deployProjectArtifact(BundleContext context)
+ throws BundleException {
+ if (!m_deployCurrent) {
+ return;
+ }
+
+ File file = m_project.getArtifact().getFile();
+ try {
+ if (file.exists()) {
+ if (file.getName().endsWith("jar")) {
+ JarFile jar = new JarFile(file);
+ if (jar.getManifest().getMainAttributes().getValue("Bundle-ManifestVersion") != null) {
+ Bundle bundle = context.installBundle(file.toURL().toString());
+ bundle.start();
+ } else {
+ System.err.println("The current artifact " + file.getName() + " is not a valid bundle");
+ }
+ } else {
+ System.err.println("The current artifact " + file.getName() + " is not a Jar file.");
+ }
+ } else {
+ System.err.println("The current artifact " + file.getName() + " does not exist.");
+ }
+ } catch (Exception e) {
+ throw new BundleException("The current project artifact cannot be installed (" + e.getMessage() + ")");
+ }
+
+
+ }
+
+
+ /**
+ * Start bundles.
+ * @param context the bundle context.
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) {
+ try {
+ installIPOJO(context);
+ installExtender(context);
+ installJunit(context);
+ deployBundles(context);
+ deployProjectArtifact(context);
+ } catch (BundleException e) {
+ System.err.println("Cannot start the framework : " + e.getMessage());
+ return;
+ }
+ }
+
+ /**
+ * Stopping methods.
+ * @param context the bundle context.
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) {
+ // Do nothing.
+ }
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Junit4osgiPlugin.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Junit4osgiPlugin.java
new file mode 100644
index 0000000..7bd7c86
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Junit4osgiPlugin.java
@@ -0,0 +1,755 @@
+/*
+ * 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.junit4osgi.plugin;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+import org.apache.felix.framework.Felix;
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+import org.apache.felix.ipojo.junit4osgi.plugin.log.LogServiceImpl;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Goal starting Felix and executing junit4osgi tests.
+ *
+ * @goal test
+ * @phase integration-test
+ * @requiresDependencyResolution runtime
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class Junit4osgiPlugin extends AbstractMojo {
+
+ /**
+ * The Maven project.
+ *
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ private MavenProject m_project;
+
+ /**
+ * Dependencies of the current plugin.
+ * @parameter expression="${plugin.artifacts}"
+ */
+ private java.util.List m_pluginArtifacts;
+
+ /**
+ * Base directory where all reports are written to.
+ *
+ * @parameter expression="${project.build.directory}/surefire-reports"
+ */
+ private File m_reportsDirectory;
+
+ /**
+ * Base directory where all reports are written to.
+ *
+ * @parameter expression="${project.build.directory}"
+ */
+ private File m_targetDir;
+
+ /**
+ * Must the current artifact be deployed?
+ *
+ * @parameter expression="${deployProjectArtifact}" default-value="true"
+ */
+ private boolean m_deployProjectArtifact;
+
+ /**
+ * Required bundles.
+ *
+ * @parameter
+ */
+ private List bundles;
+
+ /**
+ * Felix configuration.
+ *
+ * @parameter
+ */
+ private Map configuration;
+
+ /**
+ * Enables / Disables the log service provided by the plugin.
+ *
+ * @parameter expression="${logService}" default-value="true"
+ */
+ private boolean m_logEnable;
+
+ /**
+ * Number of executed test case.
+ */
+ private int m_total;
+
+ /**
+ * Number of failing test case.
+ */
+ private int m_totalFailures;
+
+ /**
+ * Number of test case in error .
+ */
+ private int m_totalErrors;
+
+ /**
+ * Test results in error.
+ */
+ private List m_errors = new ArrayList();
+
+ /**
+ * Failing test results.
+ */
+ private List m_failures = new ArrayList();
+
+ /**
+ * Test results.
+ */
+ private List m_results = new ArrayList();
+
+ /**
+ * Log Service exposed by the plug-in framework.
+ */
+ private LogServiceImpl m_logService;
+
+ /**
+ * Set this to 'true' to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you
+ * enable it using the "maven.test.skip" property, because maven.test.skip disables both running the
+ * tests and compiling the tests. Consider using the skipTests parameter instead.
+ *
+ * @parameter expression="${maven.test.skip}"
+ */
+ private boolean skip;
+
+ /**
+ * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on
+ * occasion.
+ *
+ * @parameter expression="${maven.test.failure.ignore}"
+ */
+ private boolean testFailureIgnore;
+
+ /**
+ * Set this to avoid printing test execution trace on System.out and System.err. This will be written in the
+ * reports.
+ * @parameter
+ */
+ private boolean hideOutputs;
+
+ /**
+ * Felix configuration.
+ */
+ private Map felixConf;
+
+
+ /**
+ * Executes the plug-in.
+ * @throws MojoFailureException when the test execution failed.
+ * @see org.apache.maven.plugin.AbstractMojo#execute()
+ */
+ public void execute() throws MojoFailureException {
+
+ if (skip) {
+ getLog().info("Tests are skipped");
+ return;
+ }
+
+
+ List bundles = parseBundleList();
+ bundles.addAll(getTestBundle());
+
+ List activators = new ArrayList();
+ m_logService = new LogServiceImpl();
+ if (m_logEnable) { // Starts the log service if enabled
+ activators.add(m_logService);
+ } else {
+ getLog().info("Log Service disabled");
+ }
+ activators.add(new Installer(m_pluginArtifacts, bundles, m_project, m_deployProjectArtifact));
+ felixConf = new HashMap();
+ felixConf.put("felix.systembundle.activators", activators);
+ felixConf.put("org.osgi.framework.storage.clean", "onFirstInit");
+ felixConf.put("ipojo.log.level", "WARNING");
+ // Use a boot delagation to share classes between the host and the embedded Felix.
+ // The cobertura package is used during code coverage collection
+ //felixConf.put("org.osgi.framework.bootdelegation", "net.sourceforge.cobertura.coveragedata");
+ felixConf.put("org.osgi.framework.system.packages.extra", "org.osgi.service.log;version=1.3, junit.framework;version=1.3");
+
+ //felixConf.put("org.osgi.framework.system.packages.extra", "org.osgi.service.log, junit.framework");
+
+ felixConf.put("org.osgi.framework.storage", m_targetDir.getAbsolutePath() + "/felix-cache");
+
+ felixConf.put(Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK);
+
+ if (configuration != null) {
+ felixConf.putAll(configuration);
+ // Check boot delegation
+// String bd = (String) felixConf.get("org.osgi.framework.bootdelegation");
+//// if (bd.indexOf("junit.framework") == -1) {
+//// bd.concat(", junit.framework");
+//// }
+//// if (bd.indexOf("org.osgi.service.log") == -1) {
+//// bd.concat(", org.osgi.service.log");
+//// }
+// if (bd.indexOf("net.sourceforge.cobertura.coveragedata") == -1) {
+// bd.concat(", net.sourceforge.cobertura.coveragedata");
+// }
+ }
+
+ System.out.println("");
+ System.out.println("-------------------------------------------------------");
+ System.out.println(" T E S T S");
+ System.out.println("-------------------------------------------------------");
+
+ Felix felix = new Felix(felixConf);
+ try {
+ felix.start();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+
+ getLog().info("Felix started - Waiting for stability");
+
+ waitForStability(felix.getBundleContext());
+
+ getLog().info("Bundle Stability Reached - Waiting for runner service");
+
+ Object runner = waitForRunnerService(felix.getBundleContext());
+
+ if (runner == null) {
+ throw new MojoFailureException("Cannot intialize the testing framework");
+ }
+
+ getLog().info("Runner Service available");
+
+ invokeRun(runner, felix.getBundleContext());
+
+ try {
+ felix.stop();
+ felix.waitForStop(5000);
+ // Delete felix-cache
+ File cache = new File(m_targetDir.getAbsolutePath() + "/felix-cache");
+ cache.delete();
+ } catch (Exception e) {
+ getLog().error(e);
+ }
+
+ if (m_totalErrors > 0 || m_totalFailures > 0) {
+ if (! testFailureIgnore) {
+ throw new MojoFailureException("There are test failures. \n\n"
+ + "Please refer to " + m_reportsDirectory.getAbsolutePath()
+ + " for the individual test results.");
+ } else {
+ getLog().warn("There are test failures. \n\n"
+ + "Please refer to " + m_reportsDirectory.getAbsolutePath()
+ + " for the individual test results.");
+ }
+ }
+
+ }
+
+ /**
+ * Waits for stability:
+ * <ul>
+ * <li>all bundles are activated
+ * <li>service count is stable
+ * </ul>
+ * If the stability can't be reached after a specified time,
+ * the method throws a {@link MojoFailureException}.
+ * @param context the bundle context
+ * @throws MojoFailureException when the stability can't be reach after a several attempts.
+ */
+ private void waitForStability(BundleContext context) throws MojoFailureException {
+ // Wait for bundle initialization.
+ boolean bundleStability = getBundleStability(context);
+ int count = 0;
+ while (!bundleStability && count < 500) {
+ try {
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ // Interrupted
+ }
+ count++;
+ bundleStability = getBundleStability(context);
+ }
+
+ if (count == 500) {
+ getLog().error("Bundle stability isn't reached after 500 tries");
+ dumpBundles(context);
+ throw new MojoFailureException("Cannot reach the bundle stability");
+ }
+
+ //DEBUG
+ Bundle[] bundles = context.getBundles();
+ getLog().debug("Bundles List");
+ for (int i = 0; i < bundles.length; i++) {
+ getLog().debug(bundles[i].getSymbolicName() + " - " + bundles[i].getVersion() + " - " + bundles[i].getState());
+ }
+ getLog().debug("--------------");
+ // END DEBUG
+
+ boolean serviceStability = false;
+ count = 0;
+ int count1 = 0;
+ int count2 = 0;
+ while (! serviceStability && count < 500) {
+ try {
+ ServiceReference[] refs = context.getServiceReferences((String) null, null);
+ count1 = refs.length;
+ Thread.sleep(500);
+ refs = context.getServiceReferences((String) null, null);
+ count2 = refs.length;
+ serviceStability = count1 == count2;
+ } catch (Exception e) {
+ getLog().error(e);
+ serviceStability = false;
+ // Nothing to do, while recheck the condition
+ }
+ count++;
+ }
+
+ if (count == 500) {
+ getLog().error("Service stability isn't reached after 500 tries (" + count1 + " != " + count2);
+ dumpBundles(context);
+ throw new MojoFailureException("Cannot reach the service stability");
+ }
+
+ try {
+ ServiceReference[] refs = context.getServiceReferences((String) null, null);
+ getLog().debug("Service List");
+ for (int i = 0; i < refs.length; i++) {
+ String[] itfs = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
+ List list = Arrays.asList(itfs);
+ if (list.contains("org.apache.felix.ipojo.architecture.Architecture")) {
+ getLog().debug(list.toString() + " - " + refs[i].getProperty("architecture.instance"));
+ } else {
+ getLog().debug(list.toString());
+ }
+ }
+ getLog().debug("--------------");
+ } catch (Exception e) {}
+
+ }
+
+ /**
+ * Are bundle stables.
+ * @param bc the bundle context
+ * @return <code>true</code> if every bundles are activated.
+ */
+ private boolean getBundleStability(BundleContext bc) {
+ boolean stability = true;
+ Bundle[] bundles = bc.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ stability = stability && (bundles[i].getState() == Bundle.ACTIVE);
+ }
+ return stability;
+ }
+
+ /**
+ * Computes the URL list of bundles to install from
+ * the <code>bundles</code> parameter.
+ * @return the list of url of bundles to install.
+ */
+ private List parseBundleList() {
+ List toDeploy = new ArrayList();
+ if (bundles == null) {
+ return toDeploy;
+ }
+ for (int i = 0; i < bundles.size(); i++) {
+ String bundle = (String) bundles.get(i);
+ try {
+ URL url = new URL(bundle);
+ toDeploy.add(url);
+ } catch (MalformedURLException e) {
+ // Not a valid url,
+ getLog().error(bundle + " is not a valid url, bundle ignored");
+ }
+ }
+
+ return toDeploy;
+ }
+
+ /**
+ * Computes the URL list of bundles to install from
+ * <code>test</code> scoped dependencies.
+ * @return the list of url of bundles to install.
+ */
+ private List getTestBundle() {
+ List toDeploy = new ArrayList();
+ Set dependencies = m_project.getDependencyArtifacts();
+ for (Iterator artifactIterator = dependencies.iterator(); artifactIterator.hasNext();) {
+ Artifact artifact = (Artifact) artifactIterator.next();
+ if (artifact.getScope() != null) { // Select not null scope... [Select every bundles with a scope TEST, COMPILE and RUNTIME]
+ File file = artifact.getFile();
+ try {
+ if (file.exists()) {
+ if (file.getName().endsWith("jar") && ! file.getName().startsWith("org.apache.felix.ipojo-")) {
+ JarFile jar = new JarFile(file);
+ if (jar.getManifest().getMainAttributes().getValue("Bundle-ManifestVersion") != null) {
+ toDeploy.add(file.toURI().toURL());
+ }
+ } // else {
+// getLog().info("The artifact " + artifact.getFile().getName() + " is not a Jar file.");
+// }
+ } else {
+ getLog().info("The artifact " + artifact.getFile().getName() + " does not exist.");
+ }
+ } catch (Exception e) {
+ getLog().error(file + " is not a valid bundle, this artifact is ignored");
+ }
+ }
+ }
+ return toDeploy;
+ }
+
+ /**
+ * Waits until the {@link OSGiJunitRunner} service
+ * is published.
+ * @param bc the bundle context
+ * @return the {@link OSGiJunitRunner} service object.
+ */
+ private Object waitForRunnerService(BundleContext bc) {
+ ServiceReference ref = bc.getServiceReference(org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner.class.getName());
+ int count = 0;
+ while (ref == null && count < 1000) {
+ try {
+ Thread.sleep(5);
+ count++;
+ } catch (InterruptedException e) {
+ // Nothing to do
+ }
+ ref = bc.getServiceReference(org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner.class.getName());
+ }
+ if (ref != null) {
+ return bc.getService(ref);
+ }
+ getLog().error("Junit Runner service unavailable");
+
+ dumpServices(bc);
+
+ return null;
+ }
+
+ /**
+ * Executes tests by using reflection.
+ * @param runner the {@link OSGiJunitRunner} service object
+ * @param bc the bundle context
+ */
+ private void invokeRun(Object runner, BundleContext bc) {
+ Method getTest;
+
+ try {
+ getTest = runner.getClass().getMethod("getTests", new Class[0]);
+ List tests = (List) getTest.invoke(runner, new Object[0]);
+ Method run = getRunMethod(runner);
+ for (int i = 0; i < tests.size(); i++) {
+ executeTest(runner, (Test) tests.get(i), run, bc);
+ }
+ System.out.println("\nResults :");
+ if (m_failures.size() > 0) {
+ System.out.println("\nFailed tests:");
+ for (int i = 0; i < m_failures.size(); i++) {
+ TestResult tr = (TestResult) m_failures.get(i);
+ Enumeration e = tr.failures();
+ while (e.hasMoreElements()) {
+ TestFailure tf = (TestFailure) e.nextElement();
+ System.out.println(" " + tf.toString());
+ }
+ }
+ }
+
+ if (m_failures.size() > 0) {
+ System.out.println("\nTests in error:");
+ for (int i = 0; i < m_errors.size(); i++) {
+ TestResult tr = (TestResult) m_errors.get(i);
+ Enumeration e = tr.errors();
+ while (e.hasMoreElements()) {
+ TestFailure tf = (TestFailure) e.nextElement();
+ System.out.println(" " + tf.toString());
+ }
+ }
+ }
+
+ System.out.println("\nTests run: " + m_total + ", Failures: " + m_totalFailures + ", Errors:" + m_totalErrors + "\n");
+ } catch (Exception e) {
+ getLog().error(e);
+ }
+ }
+
+ /**
+ * Gets the {@link OSGiJunitRunner#run(long)} method from the
+ * {@link OSGiJunitRunner} service object.
+ * @param runner the {@link OSGiJunitRunner} service object.
+ * @return the Method object for the <code>run</code> method.
+ */
+ private Method getRunMethod(Object runner) {
+ Method[] methods = runner.getClass().getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().equals("run")
+ && methods[i].getParameterTypes().length == 1
+ && ! methods[i].getParameterTypes()[0].equals(Long.TYPE)) {
+ return methods[i];
+ }
+ }
+ getLog().error("Cannot find the run method");
+ return null;
+ }
+
+ /**
+ * Computes the name of the given test.
+ * This method calls the {@link TestCase#getName()}
+ * method by reflection. If no success, invokes the
+ * {@link Object#toString()} method.
+ * @param test the test object.
+ * @return the name of the given test.
+ */
+ private String getTestName(Object test) {
+ try {
+ Method getName = test.getClass().getMethod("getName", new Class[0]);
+ String name = (String) getName.invoke(test, new Object[0]);
+ if (name == null) {
+ name = test.toString();
+ }
+ return name;
+ } catch (Exception e) {
+ getLog().error(e);
+ return null;
+ }
+
+ }
+
+ /**
+ * Executes the given test.
+ * @param runner the {@link OSGiJunitRunner} service object
+ * @param test the test to run
+ * @param run the {@link OSGiJunitRunner#run(long)} method
+ * @param bc the bundle context
+ */
+ private void executeTest(Object runner, Test test, Method run,
+ BundleContext bc) {
+ try {
+ XMLReport report = new XMLReport();
+ String name = getTestName(test);
+ System.out.println("Running " + name);
+
+ TestResult tr = new TestResult();
+ tr.addListener(new ResultListener(report));
+ test.run(tr);
+ m_results.add(tr);
+
+ if (tr.wasSuccessful()) {
+ System.out.println("Tests run: "
+ + tr.runCount()
+ + ", Failures: "
+ + tr.failureCount()
+ + ", Errors: "
+ + tr.errorCount()
+ + ", Time elapsed: "
+ + report.elapsedTimeAsString(report.m_endTime
+ - report.m_endTime) + " sec");
+ } else {
+ System.out.println("Tests run: "
+ + tr.runCount()
+ + ", Failures: "
+ + tr.failureCount()
+ + ", Errors: "
+ + tr.errorCount()
+ + ", Time elapsed: "
+ + report.elapsedTimeAsString(report.m_endTime
+ - report.m_endTime) + " sec <<< FAILURE!");
+ if (tr.errorCount() > 0) {
+ m_errors.add(tr);
+ }
+ if (tr.failureCount() > 0) {
+ m_failures.add(tr);
+ }
+ }
+
+ m_total += tr.runCount();
+ m_totalFailures += tr.failureCount();
+ m_totalErrors += tr.errorCount();
+
+ report.generateReport(test, tr, m_reportsDirectory, bc, felixConf);
+
+ } catch (Exception e) {
+ getLog().error(e);
+ }
+
+ }
+
+ /**
+ * Prints the bundle list.
+ * @param bc the bundle context.
+ */
+ public void dumpBundles(BundleContext bc) {
+ getLog().info("Bundles:");
+ Bundle[] bundles = bc.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ getLog().info(bundles[i].getSymbolicName() + " - " + bundles[i].getState());
+ }
+ }
+
+ /**
+ * Prints the service list.
+ * @param bc the bundle context.
+ */
+ public void dumpServices(BundleContext bc) {
+ getLog().info("Services:");
+ ServiceReference[] refs = null;
+ try {
+ refs = bc.getAllServiceReferences(null, null);
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+ for (int i = 0; i < refs.length; i++) {
+ String[] itfs = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
+ String bundle = refs[i].getBundle().getSymbolicName();
+ getLog().info(bundle + " : " + Arrays.toString(itfs));
+ }
+ }
+
+ public LogServiceImpl getLogService() {
+ return m_logService;
+ }
+
+
+ private class ResultListener implements TestListener {
+
+ /**
+ * The XML Report.
+ */
+ private XMLReport m_report;
+
+ /**
+ * Check if the test has failed or thrown an
+ * error.
+ */
+ private boolean m_abort;
+
+ /**
+ * Backup of the {@link System#out} stream.
+ */
+ private PrintStream m_outBackup = System.out;
+
+ /**
+ * Backup of the {@link System#err} stream.
+ */
+ private PrintStream m_errBackup = System.err;
+
+ /**
+ * The output stream used during the test execution.
+ */
+ private StringOutputStream m_out = new StringOutputStream();
+
+ /**
+ * The error stream used during the test execution.
+ */
+ private StringOutputStream m_err = new StringOutputStream();;
+
+ /**
+ * Creates a ResultListener.
+ * @param report the XML report
+ */
+ public ResultListener(XMLReport report) {
+ this.m_report = report;
+ }
+
+ /**
+ * An error occurs during the test execution.
+ * @param test the test in error
+ * @param throwable the thrown error
+ * @see junit.framework.TestListener#addError(junit.framework.Test, java.lang.Throwable)
+ */
+ public void addError(Test test, Throwable throwable) {
+ m_report.testError(test, throwable, m_out.toString(), m_err.toString(), getLogService().getLoggedMessages());
+ m_abort = true;
+ }
+
+ /**
+ * An failure occurs during the test execution.
+ * @param test the failing test
+ * @param assertionfailederror the failure
+ * @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError)
+ */
+ public void addFailure(Test test,
+ AssertionFailedError assertionfailederror) {
+ m_report.testFailed(test, assertionfailederror, m_out.toString(), m_err.toString(), getLogService().getLoggedMessages());
+ m_abort = true;
+
+ }
+
+ /**
+ * The test ends.
+ * @param test the test
+ * @see junit.framework.TestListener#endTest(junit.framework.Test)
+ */
+ public void endTest(Test test) {
+ if (!m_abort) {
+ m_report.testSucceeded(test);
+ }
+ System.setErr(m_errBackup);
+ System.setOut(m_outBackup);
+ getLogService().reset();
+ }
+
+ /**
+ * The test starts.
+ * @param test the test
+ * @see junit.framework.TestListener#startTest(junit.framework.Test)
+ */
+ public void startTest(Test test) {
+ m_abort = false;
+ m_report.testStarting();
+ System.setErr(new ReportPrintStream(m_err,m_errBackup, hideOutputs));
+ System.setOut(new ReportPrintStream(m_out, m_outBackup, hideOutputs));
+ getLogService().enableOutputStream();
+ }
+
+ }
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Report.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Report.java
new file mode 100644
index 0000000..16ab48b
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/Report.java
@@ -0,0 +1,239 @@
+/*
+ * 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.junit4osgi.plugin;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import junit.framework.Test;
+
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Test report.
+ * This class is provides the basics to support several output format.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Report {
+
+ /**
+ * New line constant.
+ */
+ protected static final String NL = System.getProperty("line.separator");
+
+ /**
+ * Number of ran tests.
+ */
+ protected int m_completedCount;
+
+ /**
+ * Number of errors.
+ */
+ protected int m_errorsCount;
+
+ /**
+ * Number of failures.
+ */
+ protected int m_failuresCount;
+
+
+ /**
+ * Time at the beginning of the test execution.
+ */
+ protected long m_startTime;
+
+ /**
+ * Time at the end of the test execution.
+ */
+ protected long m_endTime;
+
+ /**
+ * Failing tests.
+ */
+ private List m_failureSources = new ArrayList();
+
+ /**
+ * Tests in error.
+ */
+ private List m_errorSources = new ArrayList();
+
+ /**
+ * Double format.
+ */
+ private NumberFormat m_numberFormat = NumberFormat.getInstance(Locale.US);
+
+ /**
+ * Gets failing tests.
+ * @return the list of failing tests.
+ */
+ public List getFailureSources() {
+ return this.m_failureSources;
+ }
+
+ /**
+ * Gets tests in error.
+ * @return the list of test throwing unexpected exceptions
+ */
+ public List getErrorSources() {
+ return this.m_errorSources;
+ }
+
+ /**
+ * Callback called when a test starts.
+ */
+ public void testStarting() {
+ m_startTime = System.currentTimeMillis();
+ }
+
+ /**
+ * Callback called when a test ends successfully.
+ */
+ public void testSucceeded() {
+ endTest();
+ }
+
+ /**
+ * Callback called when a test throws an unexpected error.
+ * @param test the test in error.
+ */
+ public void testError(Test test) {
+ ++m_errorsCount;
+ m_errorSources.add(test.toString());
+ endTest();
+ }
+
+ /**
+ * Callback called when a test fails.
+ * @param test the failing test.
+ */
+ public void testFailed(Test test) {
+ ++m_failuresCount;
+ m_failureSources.add(test.toString());
+ endTest();
+ }
+
+ /**
+ * Callback called when a test ends.
+ * This method handles common action when a test ends.
+ */
+ private void endTest() {
+ ++m_completedCount;
+
+ m_endTime = System.currentTimeMillis();
+
+ if (m_startTime == 0) {
+ m_startTime = m_endTime;
+ }
+ }
+
+
+ public int getNumErrors() {
+ return m_errorsCount;
+ }
+
+ public int getNumFailures() {
+ return m_failuresCount;
+ }
+
+ public int getNumTests() {
+ return m_completedCount;
+ }
+
+ /**
+ * Reset the report.
+ */
+ public void reset() {
+ m_errorsCount = 0;
+
+ m_failuresCount = 0;
+
+ m_completedCount = 0;
+
+ this.m_failureSources = new ArrayList();
+
+ this.m_errorSources = new ArrayList();
+
+ }
+
+
+ /**
+ * Returns the formatted String to display the given double.
+ * @param runTime the elapsed time
+ * @return the String displaying the elapsed time
+ */
+ protected String elapsedTimeAsString(long runTime) {
+ return m_numberFormat.format((double) runTime / 1000);
+ }
+
+ /**
+ * Returns the stack trace as String.
+ * @param test the test
+ * @param e the exception
+ * @return stack trace as string.
+ */
+ protected String getStackTrace(Test test, Throwable e) {
+
+ if (e == null) {
+ return "";
+ }
+
+ StringWriter w = new StringWriter();
+ if (e != null) {
+ e.printStackTrace(new PrintWriter(w));
+ w.flush();
+ }
+ String text = w.toString();
+ String marker = "at " + test.toString();
+
+ String[] lines = StringUtils.split(text, "\n");
+ int lastLine = lines.length - 1;
+ int causedByLine = -1;
+ // skip first
+ for (int i = 1; i < lines.length; i++) {
+ String line = lines[i].trim();
+ if (line.startsWith(marker)) {
+ lastLine = i;
+ } else if (line.startsWith("Caused by")) {
+ causedByLine = i;
+ break;
+ }
+ }
+
+ StringBuffer trace = new StringBuffer();
+ for (int i = 0; i <= lastLine; i++) {
+ trace.append(lines[i]);
+ trace.append("\n");
+ }
+
+ if (causedByLine != -1) {
+ for (int i = causedByLine; i < lines.length; i++) {
+ trace.append(lines[i]);
+ trace.append("\n");
+ }
+ }
+ return trace.toString();
+ }
+
+
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/ReportPrintStream.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/ReportPrintStream.java
new file mode 100644
index 0000000..97e8fd3
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/ReportPrintStream.java
@@ -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.
+ */
+package org.apache.felix.ipojo.junit4osgi.plugin;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Print stream dispatching on a given one and storing written data
+ * in a output stream.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ReportPrintStream extends PrintStream {
+
+ private PrintStream m_stream;
+
+ private boolean m_duplicate;
+
+ public ReportPrintStream(OutputStream out, PrintStream def, boolean hideOutput) {
+ super(out);
+ m_stream = def;
+ m_duplicate = ! hideOutput;
+ }
+
+ public void println() {
+ if (m_duplicate) { m_stream.println(); }
+ super.println();
+ }
+
+
+ public void println(boolean x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(char x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(char[] x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(double x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(float x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(int x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+
+ public void println(long x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(Object x) {
+ if (m_duplicate) { m_stream.println(x); }
+ super.println(x);
+ }
+
+
+ public void println(String s) {
+ if (m_duplicate) { m_stream.println(s); }
+ super.println(s);
+ }
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/StringOutputStream.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/StringOutputStream.java
new file mode 100644
index 0000000..fa0a1f7
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/StringOutputStream.java
@@ -0,0 +1,121 @@
+/*
+ * 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.junit4osgi.plugin;
+
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * Provides an OutputStream to an internal String. Internally converts bytes to
+ * a Strings and stores them in an internal StringBuffer.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StringOutputStream extends OutputStream implements Serializable {
+
+ /**
+ * Id.
+ */
+ private static final long serialVersionUID = -5912060965986156224L;
+
+ /**
+ * The internal destination StringBuffer.
+ */
+ protected StringBuffer m_buffer = null;
+
+ /**
+ * Creates new StringOutputStream, makes a new internal StringBuffer.
+ */
+ public StringOutputStream() {
+ super();
+ m_buffer = new StringBuffer();
+ }
+
+ /**
+ * Returns the content of the internal StringBuffer as a String, the result
+ * of all writing to this OutputStream.
+ *
+ * @return returns the content of the internal StringBuffer
+ */
+ public String toString() {
+ return m_buffer.toString();
+ }
+
+ /**
+ * Sets the internal StringBuffer to null.
+ */
+ public void close() {
+ m_buffer = null;
+
+ }
+
+ /**
+ * Writes and appends a byte array to StringOutputStream.
+ *
+ * @param b the byte array
+ * @param off the byte array starting index
+ * @param len the number of bytes from byte array to write to the stream
+ */
+ public void write(byte[] b, int off, int len) {
+ if ((off < 0) || (len < 0) || (off + len) > b.length) {
+ throw new IndexOutOfBoundsException(
+ "StringOutputStream.write: Parameters out of bounds.");
+ }
+ byte[] bytes = new byte[len];
+ for (int i = 0; i < len; i++) {
+ bytes[i] = b[off];
+ off++;
+ }
+ m_buffer.append(toCharArray(bytes));
+ }
+
+ /**
+ * Writes and appends a single byte to StringOutputStream.
+ *
+ * @param b the byte as an int to add
+ */
+ public void write(int b) {
+ m_buffer.append((char) b);
+ }
+
+ /**
+ * Writes and appends a String to StringOutputStream.
+ *
+ * @param s the String to add
+ */
+ public void write(String s) {
+ m_buffer.append(s);
+ }
+
+ /**
+ * Converts byte array to char array.
+ * @param barr input byte array
+ * @return the char array corresponding to the
+ * given byte array
+ */
+ public static char[] toCharArray(byte[] barr) {
+ if (barr == null) {
+ return null;
+ }
+ char[] carr = new char[barr.length];
+ for (int i = 0; i < barr.length; i++) {
+ carr[i] = (char) barr[i];
+ }
+ return carr;
+ }
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/XMLReport.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/XMLReport.java
new file mode 100644
index 0000000..9e2632e
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/XMLReport.java
@@ -0,0 +1,359 @@
+/*
+ * 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.junit4osgi.plugin;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This class generates test result as XML files compatible with Surefire.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class XMLReport extends Report {
+
+ /**
+ * List of results.
+ */
+ private List m_results = new ArrayList();
+
+ /**
+ * A test ends successfully.
+ * @param test the test executed successfully.
+ */
+ public void testSucceeded(Test test) {
+ super.testSucceeded();
+
+ long runTime = this.m_endTime - this.m_startTime;
+
+ Xpp3Dom testCase = createTestElement(test, runTime);
+
+ m_results.add(testCase);
+ }
+
+ /**
+ * A test throws an unexpected errors.
+ * @param test the test in error
+ * @param e the thrown exception
+ * @param out the output messages printed during the test execution
+ * @param err the error messages printed during the test execution
+ * @param log the messages logged during the test execution
+ */
+ public void testError(Test test, Throwable e, String out, String err, String log) {
+ super.testError(test);
+
+ writeTestProblems(test, e, "error", out, err, log);
+ }
+
+ /**
+ * A test fails.
+ * @param test the failing test
+ * @param e the thrown failure
+ * @param out the output messages printed during the test execution
+ * @param err the error messages printed during the test execution
+ * @param log the messages logged during the test execution
+ */
+ public void testFailed(Test test, Throwable e, String out, String err, String log) {
+ super.testFailed(test);
+
+ writeTestProblems(test, e, "failure", out, err, log);
+ }
+
+ /**
+ * Utility method writing failed and in error test result in the report.
+ * @param test the test
+ * @param e the thrown error
+ * @param name type of failure ("error" or "failure")
+ * @param out the output messages printed during the test execution
+ * @param err the error messages printed during the test execution
+ * @param log the messages logged during the test execution
+ */
+ private void writeTestProblems(Test test, Throwable e, String name, String out, String err, String log) {
+
+ long runTime = m_endTime - m_startTime;
+
+ Xpp3Dom testCase = createTestElement(test, runTime);
+
+ Xpp3Dom element = createElement(testCase, name);
+
+ String stackTrace = getStackTrace(test, e);
+
+ Throwable t = e;
+
+ if (t != null) {
+
+ String message = t.getMessage();
+
+ if (message != null) {
+ element.setAttribute("message", message);
+
+ element.setAttribute("type",
+ stackTrace.indexOf(":") > -1 ? stackTrace.substring(0,
+ stackTrace.indexOf(":")) : stackTrace);
+ } else {
+ element.setAttribute("type", new StringTokenizer(stackTrace)
+ .nextToken());
+ }
+ }
+
+ if (stackTrace != null) {
+ element.setValue(stackTrace);
+ }
+
+ addOutputStreamElement(out, "system-out", testCase);
+
+ addOutputStreamElement(err, "system-err", testCase);
+
+ if (log != null) {
+ addOutputStreamElement(log, "log-service", testCase);
+ }
+
+ m_results.add(testCase);
+ }
+
+ /**
+ * Generates the XML reports.
+ * @param test the test
+ * @param tr the test result
+ * @param reportsDirectory the directory in which reports are created.
+ * @param bc the bundle context (to get installed bundles)
+ * @param configuration the Felix configuration
+ * @throws Exception when the XML report cannot be generated correctly
+ */
+ public void generateReport(Test test, TestResult tr, File reportsDirectory,
+ BundleContext bc, Map configuration) throws Exception {
+ long runTime = this.m_endTime - this.m_startTime;
+
+ Xpp3Dom testSuite = createTestSuiteElement(test, runTime);
+
+ showProperties(testSuite, bc, configuration);
+
+ testSuite.setAttribute("tests", String.valueOf(tr.runCount()));
+
+ testSuite.setAttribute("errors", String.valueOf(tr.errorCount()));
+
+ testSuite.setAttribute("failures", String.valueOf(tr.failureCount()));
+
+ for (Iterator i = m_results.iterator(); i.hasNext();) {
+ Xpp3Dom testcase = (Xpp3Dom) i.next();
+ testSuite.addChild(testcase);
+ }
+
+ File reportFile = new File(reportsDirectory, "TEST-"
+ + getReportName(test).replace(' ', '_') + ".xml");
+
+ File reportDir = reportFile.getParentFile();
+
+ reportDir.mkdirs();
+
+ PrintWriter writer = null;
+
+ try {
+ writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
+ new FileOutputStream(reportFile), "UTF-8")));
+
+ writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + NL);
+
+ Xpp3DomWriter.write(new PrettyPrintXMLWriter(writer), testSuite);
+ } catch (UnsupportedEncodingException e) {
+ throw new Exception("Unable to use UTF-8 encoding", e);
+ } catch (FileNotFoundException e) {
+ throw new Exception("Unable to create file: " + e.getMessage(), e);
+ } finally {
+ IOUtil.close(writer);
+ }
+ }
+
+ /**
+ * Creates a XML test case element.
+ * @param test the test
+ * @param runTime the elapsed time to execute the test.
+ * @return the XML element describing the given test.
+ */
+ private Xpp3Dom createTestElement(Test test, long runTime) {
+ Xpp3Dom testCase = new Xpp3Dom("testcase");
+ testCase.setAttribute("name", getReportName(test));
+ double time = (double) runTime / (double) 1000;
+ testCase.setAttribute("time", Double.toString(time));
+ testCase.setAttribute("classname", test.getClass().getName());
+ return testCase;
+ }
+
+ /**
+ * Creates a XML test suite element.
+ * @param test the test
+ * @param runTime the elapsed time to execute the test suite.
+ * @return the XML element describing the given test suite.
+ */
+ private Xpp3Dom createTestSuiteElement(Test test, long runTime) {
+ Xpp3Dom testCase = new Xpp3Dom("testsuite");
+ testCase.setAttribute("name", getReportName(test));
+ testCase.setAttribute("time", Long.toString(runTime));
+ return testCase;
+ }
+
+ /**
+ * Computes report name.
+ * @param test the test
+ * @return the report name
+ */
+ private static String getReportName(Test test) {
+ String report = test.toString();
+
+ if (report.indexOf("(") > 0) {
+ report = report.substring(0, report.indexOf("("));
+ }
+ return report;
+ }
+
+ /**
+ * Creates an XML element.
+ * @param element the parent element
+ * @param name the name of the element to create
+ * @return the resulting XML tree.
+ */
+ private Xpp3Dom createElement(Xpp3Dom element, String name) {
+ Xpp3Dom component = new Xpp3Dom(name);
+
+ element.addChild(component);
+
+ return component;
+ }
+
+ /**
+ * Adds system properties to the XML report.
+ * This method also adds installed bundles.
+ * @param testSuite the XML element.
+ * @param bc the bundle context
+ * @param configuration the configuration of the underlying OSGi platform
+ */
+ private void showProperties(Xpp3Dom testSuite, BundleContext bc, Map configuration) {
+ Xpp3Dom properties = createElement(testSuite, "properties");
+
+ Properties systemProperties = System.getProperties();
+
+ if (systemProperties != null) {
+ Enumeration propertyKeys = systemProperties.propertyNames();
+
+ while (propertyKeys.hasMoreElements()) {
+ String key = (String) propertyKeys.nextElement();
+
+ String value = systemProperties.getProperty(key);
+
+ if (value == null) {
+ value = "null";
+ }
+
+ Xpp3Dom property = createElement(properties, "property");
+
+ property.setAttribute("name", key);
+
+ property.setAttribute("value", value);
+
+ }
+ }
+
+ if (configuration != null) {
+ Iterator it = configuration.keySet().iterator();
+
+ while (it.hasNext()) {
+ String key = (String) it.next();
+
+ Object obj = (Object) configuration.get(key);
+ String value = null;
+ if (obj == null) {
+ value = "null";
+ } else if (obj instanceof String) {
+ value = (String) obj;
+ } else {
+ value = obj.toString();
+ }
+
+ Xpp3Dom property = createElement(properties, "property");
+
+ property.setAttribute("name", key);
+
+ property.setAttribute("value", value);
+
+ }
+ }
+
+ Xpp3Dom bundle = createElement(properties, "property");
+ Bundle[] bundles = bc.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ String sn = bundles[i].getSymbolicName();
+ String state = "UNKNOWN";
+ switch (bundles[i].getState()) {
+ case Bundle.ACTIVE:
+ state = "ACTIVE";
+ break;
+ case Bundle.INSTALLED:
+ state = "INSTALLED";
+ break;
+ case Bundle.RESOLVED:
+ state = "RESOLVED";
+ break;
+ case Bundle.UNINSTALLED:
+ state = "UNINSTALLED";
+ break;
+ default:
+ break;
+ }
+ bundle.setAttribute("name", "bundle-" + sn);
+ bundle.setAttribute("value", state);
+ }
+
+ }
+
+ /**
+ * Adds messages written during the test execution in the
+ * XML tree.
+ * @param stdOut the messages
+ * @param name the name of the stream (out, error, log)
+ * @param testCase the XML tree
+ */
+ private void addOutputStreamElement(String stdOut, String name,
+ Xpp3Dom testCase) {
+ if (stdOut != null && stdOut.trim().length() > 0) {
+ createElement(testCase, name).setValue(stdOut);
+ }
+ }
+
+}
diff --git a/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/log/LogServiceImpl.java b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/log/LogServiceImpl.java
new file mode 100644
index 0000000..bb795ac
--- /dev/null
+++ b/ipojo/junit4osgi/maven-junit4osgi-plugin/src/main/java/org/apache/felix/ipojo/junit4osgi/plugin/log/LogServiceImpl.java
@@ -0,0 +1,187 @@
+/*
+ * 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.junit4osgi.plugin.log;
+
+import org.apache.felix.ipojo.junit4osgi.plugin.StringOutputStream;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * An implementation of the log service to collect logged messages.
+ * This service implementation is also {@link BundleActivator} and is
+ * activated when the embedded OSGi platform starts.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LogServiceImpl implements LogService, BundleActivator {
+
+ /**
+ * Default output stream (not collected).
+ */
+ private StringOutputStream m_defaultStream;
+
+ /**
+ * Collected output stream.
+ */
+ private StringOutputStream m_outputStream;
+
+ /**
+ * Creates the log service object.
+ */
+ public LogServiceImpl() {
+ m_defaultStream = new StringOutputStream();
+ }
+
+ /**
+ * Enables the log messages collection.
+ */
+ public void enableOutputStream() {
+ m_outputStream = new StringOutputStream();
+ }
+
+ /**
+ * Get collected log messages.
+ * @return the String containing the logged messages.
+ */
+ public String getLoggedMessages() {
+ return m_outputStream.toString();
+ }
+
+ /**
+ * Re-initializes the collected message list.
+ */
+ public void reset() {
+ m_outputStream = null;
+ }
+
+ /**
+ * Logs a message.
+ * @param arg0 the log level
+ * @param arg1 the message
+ * @see org.osgi.service.log.LogService#log(int, java.lang.String)
+ */
+ public void log(int arg0, String arg1) {
+ write(computeLogMessage(arg0, arg1, null));
+ }
+
+ /**
+ * Logs a message with an attached exception.
+ * @param arg0 the log level
+ * @param arg1 the message
+ * @param arg2 the associated exception
+ * @see org.osgi.service.log.LogService#log(int, java.lang.String, java.lang.Throwable)
+ */
+ public void log(int arg0, String arg1, Throwable arg2) {
+ write(computeLogMessage(arg0, arg1, arg2));
+ }
+
+ /**
+ * Logs a message raised by the given service reference.
+ * @param arg0 the service reference
+ * @param arg1 the log level
+ * @param arg2 the message
+ * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, int, java.lang.String)
+ */
+ public void log(ServiceReference arg0, int arg1, String arg2) {
+ write(computeLogMessage(arg1, arg2, null));
+ }
+
+ /**
+ * Logs a message raised by the given service reference
+ * associated with an exception.
+ * @param arg0 the service reference
+ * @param arg1 the log level
+ * @param arg2 the message
+ * @param arg3 the exception
+ * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, int, java.lang.String)
+ */
+ public void log(ServiceReference arg0, int arg1, String arg2, Throwable arg3) {
+ write(computeLogMessage(arg1, arg2, arg3));
+ }
+
+ /**
+ * Computes the string from the message.
+ * @param level the log level
+ * @param msg the message
+ * @param exception the exception (can be <code>null</code>
+ * @return the resulting String
+ */
+ private String computeLogMessage(int level, String msg, Throwable exception) {
+ String message = null;
+ switch (level) {
+ case LogService.LOG_DEBUG:
+ message = "[DEBUG] " + msg;
+ break;
+ case LogService.LOG_ERROR:
+ message = "[ERROR] " + msg;
+ break;
+ case LogService.LOG_INFO:
+ message = "[INFO] " + msg;
+ break;
+ case LogService.LOG_WARNING:
+ message = "[WARNING] " + msg;
+ break;
+ default:
+ break;
+ }
+
+ if (exception != null) {
+ message = message + " : " + exception.getMessage() + "\n";
+ }
+
+ return message;
+ }
+
+ /**
+ * Writes the given message in the adequate output stream.
+ * @param log the message
+ */
+ public void write(String log) {
+ if (m_outputStream != null) {
+ m_outputStream.write(log);
+ } else {
+ m_defaultStream.write(log);
+ }
+ }
+
+ /**
+ * Stars the log service implementation:
+ * Registers the service.
+ * @param bc the bundle context.
+ * @throws Exception should not happen.
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bc) throws Exception {
+ bc.registerService(LogService.class.getName(), this, null);
+ }
+
+ /**
+ * Stops the log service implementation.
+ * Does nothing.
+ * @param arg0 the bundle context
+ * @throws Exception should not happen.
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext arg0) throws Exception {
+ // Nothing to do.
+
+ }
+
+}
diff --git a/ipojo/junit4osgi/pom.xml b/ipojo/junit4osgi/pom.xml
new file mode 100644
index 0000000..72457e9
--- /dev/null
+++ b/ipojo/junit4osgi/pom.xml
@@ -0,0 +1,59 @@
+<!--
+ 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>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>Junit4OSGi</artifactId>
+ <groupId>org.apache.felix</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Junit4OSGi</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>junit4osgi</module>
+ <module>felix-command</module>
+ <module>maven-junit4osgi-plugin</module>
+ <module>immediate-launcher</module>
+ </modules>
+
+ <profiles>
+ <profile>
+ <id>java5</id>
+ <activation>
+ <jdk>1.5</jdk>
+ </activation>
+ <modules>
+ <module>swing-runner</module>
+ </modules>
+ </profile>
+ <profile>
+ <id>java6</id>
+ <activation>
+ <jdk>1.6</jdk>
+ </activation>
+ <modules>
+ <module>swing-runner</module>
+ </modules>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/junit4osgi/swing-runner/LICENSE b/ipojo/junit4osgi/swing-runner/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/ipojo/junit4osgi/swing-runner/NOTICE b/ipojo/junit4osgi/swing-runner/NOTICE
new file mode 100644
index 0000000..18acb79
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/NOTICE
@@ -0,0 +1,27 @@
+Apache Felix iPOJO junit4osgi Swing Runner
+Copyright 2008-2009 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+This product uses software developed by
+Junit project (http://junit.org)
+Licensed under Common Public License 1.0.
+
+III. License Summary
+- Apache License 2.0
+- Common Public License 1.0
diff --git a/ipojo/junit4osgi/swing-runner/doc/changelog.txt b/ipojo/junit4osgi/swing-runner/doc/changelog.txt
new file mode 100644
index 0000000..524e88b
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/doc/changelog.txt
@@ -0,0 +1,3 @@
+Version 1.0.0
+-------------
+ * Initial release
\ No newline at end of file
diff --git a/ipojo/junit4osgi/swing-runner/metadata.xml b/ipojo/junit4osgi/swing-runner/metadata.xml
new file mode 100644
index 0000000..958bfc4
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/metadata.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<iPOJO>
+ <component
+ classname="org.apache.felix.ipojo.junit4osgi.command.SwingRunner">
+ <requires field="m_runner" />
+ <callback method="stop" transition="invalidate" />
+ <callback method="start" transition="validate" />
+ </component>
+ <instance
+ component="org.apache.felix.ipojo.junit4osgi.command.SwingRunner" />
+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/junit4osgi/swing-runner/pom.xml b/ipojo/junit4osgi/swing-runner/pom.xml
new file mode 100644
index 0000000..0716a0a
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/pom.xml
@@ -0,0 +1,104 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Junit4Osgi-Swing-GUI</name>
+ <artifactId>org.apache.felix.ipojo.junit4osgi.swing-gui</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.5</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO OSGi Junit Runner - Swing Gui</Bundle-Name>
+ <Bundle-SymbolicName> ${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package> org.apache.felix.ipojo.junit4osgi.command
+ </Private-Package>
+ <Import-Package>org.osgi.framework;version=1.3,*
+ </Import-Package>
+ <_plugin>org.apache.felix.ipojo.bnd.PojoizationPlugin;metadata=${basedir}/metadata.xml;use-local-schemas=true</_plugin>
+ </instructions>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin
+ </artifactId>
+ <configuration>
+ <configLocation>
+ http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml
+ </configLocation>
+ <violationSeverity>error</violationSeverity>
+ </configuration>
+ </plugin>
+ </plugins>
+</build>
+</project>
diff --git a/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java
new file mode 100644
index 0000000..3370f1a
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java
@@ -0,0 +1,69 @@
+/*
+ * 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.junit4osgi.command;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/**
+ * Test result renderer.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResultCellRenderer extends DefaultTableCellRenderer {
+
+ /**
+ * UUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Renderer method.
+ * @param table the table
+ * @param value the value
+ * @param isSelected is the cell selected
+ * @param hasFocus has the cell the focus
+ * @param row the cell row
+ * @param column the cell column
+ * @return the resulting component
+ * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
+ */
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+
+ ResultTableModel results = (ResultTableModel) table.getModel();
+ String status = (String) results.getValueAt(row, column);
+ if (status.equals(ResultTableModel.SUCCESS)) {
+ c.setForeground(Color.GREEN);
+ setToolTipText(results.getMessage(row, column));
+ }
+ if (status.equals(ResultTableModel.FAILURE)) {
+ c.setForeground(Color.ORANGE);
+ setToolTipText(results.getMessage(row, column));
+ }
+ if (status.equals(ResultTableModel.ERROR)) {
+ c.setForeground(Color.RED);
+ setToolTipText(results.getMessage(row, column));
+ }
+
+ return c;
+ }
+}
diff --git a/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.java b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.java
new file mode 100644
index 0000000..bf457ba
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.java
@@ -0,0 +1,278 @@
+/*
+ * 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.junit4osgi.command;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+/**
+ * Result Table Model.
+ * Store the results of executed tests.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResultTableModel extends AbstractTableModel {
+
+ /**
+ * Success String.
+ */
+ public static final String SUCCESS = "success";
+
+ /**
+ * Failure String.
+ */
+ public static final String FAILURE = "failure";
+
+ /**
+ * Error String.
+ */
+ public static final String ERROR = "error";
+
+ /**
+ * UUDI.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * List of results.
+ */
+ private List<TestRecord> m_results = new ArrayList<TestRecord>();
+
+ public int getRowCount() {
+ return m_results.size();
+ }
+
+ public int getColumnCount() {
+ return 2;
+ }
+
+ /**
+ * Adds a failing test.
+ * @param t the test
+ * @param e the assertion error
+ */
+ public void addTest(Test t, AssertionFailedError e) {
+ TestRecord rec = new TestRecord(t, e);
+ m_results.add(rec);
+ fireTableDataChanged();
+ }
+
+ /**
+ * Adds a test in error.
+ * @param t the test
+ * @param e the thrown error
+ */
+ public void addTest(Test t, Throwable e) {
+ TestRecord rec = new TestRecord(t, e);
+ m_results.add(rec);
+ fireTableDataChanged();
+ }
+
+ /**
+ * Adds a sucessfull test.
+ * @param t the test
+ */
+ public void addTest(Test t) {
+ if (!contains(t)) {
+ TestRecord rec = new TestRecord(t);
+ m_results.add(rec);
+ fireTableDataChanged();
+ }
+ }
+
+ public int getTestCount() {
+ return m_results.size();
+ }
+
+ /**
+ * Gets the number of success.
+ * @return the number of success
+ */
+ public int getSucess() {
+ int count = 0;
+ for (TestRecord test : m_results) {
+ if (test.m_wasSucessFull) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Gets the number of errors.
+ * @return the number of errors
+ */
+ public int getErrors() {
+ int count = 0;
+ for (TestRecord test : m_results) {
+ if (test.m_error != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Gets the number of failures.
+ * @return the number of failures
+ */
+ public int getFailures() {
+ int count = 0;
+ for (TestRecord test : m_results) {
+ if (test.m_failure != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+
+ /**
+ * Does the result list contains the given test.
+ * @param t the test
+ * @return <code>true</code> if the list contains the test.
+ */
+ private boolean contains(Test t) {
+ for (TestRecord test : m_results) {
+ if (test.m_test.equals(t)) { return true; }
+ }
+ return false;
+ }
+
+ /**
+ * Clear the list.
+ */
+ public void clear() {
+ m_results.clear();
+ fireTableDataChanged();
+ }
+
+ /**
+ * Get the Object placed in the JTable.
+ * @param rowIndex the row
+ * @param columnIndex the column
+ * @return the object
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ if (columnIndex == 0) { return m_results.get(rowIndex).m_test; }
+ if (columnIndex == 1) {
+ TestRecord tr = m_results.get(rowIndex);
+ if (tr.m_wasSucessFull) { return SUCCESS; }
+ if (tr.m_failure != null) { return FAILURE; }
+ if (tr.m_error != null) { return ERROR; }
+ }
+ return null;
+ }
+
+ /**
+ * Gets column names.
+ * @param column the column
+ * @return the column name
+ * @see javax.swing.table.AbstractTableModel#getColumnName(int)
+ */
+ public String getColumnName(int column) {
+ if (column == 0) { return "Test"; }
+
+ if (column == 1) { return "Status"; }
+
+ return null;
+ }
+
+ /**
+ * Gets the message.
+ * @param row the row
+ * @param column the column
+ * @return the message for this cell
+ */
+ public String getMessage(int row, int column) {
+ if (row == -1) { return null; }
+ TestRecord rec = m_results.get(row);
+ if (rec.m_wasSucessFull) { return "The test " + rec.m_test + " was executed sucessfully."; }
+ if (rec.m_failure != null) { return "The test " + rec.m_test + " has failed : \n" + rec.m_failure.getMessage(); }
+ if (rec.m_error != null) {
+ String message = "The test " + rec.m_test + " has thrown an error : \n" + rec.m_error.getMessage();
+ StringWriter sw = new StringWriter();
+ rec.m_error.printStackTrace(new PrintWriter(sw));
+ message += "\n" + sw.toString();
+ return message;
+ }
+ return "";
+ }
+
+ private class TestRecord {
+ /**
+ * Was the test successful?
+ */
+ private boolean m_wasSucessFull;
+
+ /**
+ * The test.
+ */
+ private Test m_test;
+
+ /**
+ * The failure.
+ */
+ private AssertionFailedError m_failure;
+
+ /**
+ * The error.
+ */
+ private Throwable m_error;
+
+ /**
+ * Creates a TestRecord.
+ * @param t the test
+ * @param e the failure
+ */
+ public TestRecord(Test t, AssertionFailedError e) {
+ m_test = t;
+ m_wasSucessFull = false;
+ m_failure = e;
+ }
+
+ /**
+ * Creates a TestRecord.
+ * @param t the test
+ * @param e the error
+ */
+ public TestRecord(Test t, Throwable e) {
+ m_test = t;
+ m_wasSucessFull = false;
+ m_error = e;
+ }
+
+ /**
+ * Creates a TestRecord.
+ * @param t the test
+ */
+ public TestRecord(Test t) {
+ m_test = t;
+ m_wasSucessFull = true;
+ }
+ }
+
+}
diff --git a/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form
new file mode 100644
index 0000000..d7fc050
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.5" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+ <NonVisualComponents>
+ <Container class="javax.swing.JDialog" name="m_resultDialog">
+ <Properties>
+ <Property name="defaultCloseOperation" type="int" value="0"/>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[320, 250]"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="windowClosed" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="onDialogClosed"/>
+ <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="onDialogClosed"/>
+ </Events>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+ <SubComponents>
+ <Container class="javax.swing.JScrollPane" name="m_message">
+ <Properties>
+ <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+ <Border info="null"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[300, 202]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[300, 202]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+ <BorderConstraints direction="Center"/>
+ </Constraint>
+ </Constraints>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JTextArea" name="m_messageArea">
+ <Properties>
+ <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+ <Color blue="f0" green="f0" id="Panel.background" palette="3" red="f0" type="palette"/>
+ </Property>
+ <Property name="columns" type="int" value="20"/>
+ <Property name="editable" type="boolean" value="false"/>
+ <Property name="lineWrap" type="boolean" value="true"/>
+ <Property name="rows" type="int" value="5"/>
+ <Property name="wrapStyleWord" type="boolean" value="true"/>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[300, 250]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[250, 200]"/>
+ </Property>
+ </Properties>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Component class="javax.swing.JButton" name="m_ok">
+ <Properties>
+ <Property name="text" type="java.lang.String" value="Ok"/>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[120, 23]"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="m_okActionPerformed"/>
+ </Events>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+ <BorderConstraints direction="South"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ </SubComponents>
+ </Container>
+ </NonVisualComponents>
+ <Properties>
+ <Property name="defaultCloseOperation" type="int" value="2"/>
+ <Property name="title" type="java.lang.String" value="FX Junit Runner"/>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ </Properties>
+ <SyntheticProperties>
+ <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+ </SyntheticProperties>
+ <AuxValues>
+ <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+ </AuxValues>
+
+ <Layout>
+ <DimensionLayout dim="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="m_resultScroll" alignment="1" pref="598" max="32767" attributes="0"/>
+ <Group type="102" alignment="0" attributes="0">
+ <Component id="m_statusBar" max="32767" attributes="0"/>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="m_executedResults" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <Group type="102" alignment="1" attributes="0">
+ <Group type="103" groupAlignment="1" attributes="0">
+ <Component id="txtSearchTest" alignment="0" max="32767" attributes="0"/>
+ <Component id="m_suiteScroll" pref="492" max="32767" attributes="0"/>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" max="-2" attributes="0">
+ <Component id="m_executeButton" max="32767" attributes="1"/>
+ <Component id="m_allButton" alignment="0" max="32767" attributes="1"/>
+ <Component id="btnSearch" alignment="0" max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ <DimensionLayout dim="1">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="txtSearchTest" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="btnSearch" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <Component id="m_allButton" min="-2" max="-2" attributes="0"/>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="m_executeButton" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <Component id="m_suiteScroll" pref="152" max="32767" attributes="0"/>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="m_resultScroll" min="-2" pref="415" max="-2" attributes="0"/>
+ <EmptySpace type="separate" max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="m_executedResults" min="-2" max="-2" attributes="0"/>
+ <Component id="m_statusBar" alignment="0" min="-2" max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ </Layout>
+ <SubComponents>
+ <Container class="javax.swing.JPanel" name="m_statusBar">
+
+ <Layout>
+ <DimensionLayout dim="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Component id="m_progress" alignment="0" pref="466" max="32767" attributes="0"/>
+ </Group>
+ </DimensionLayout>
+ <DimensionLayout dim="1">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" alignment="0" attributes="0">
+ <Component id="m_progress" min="-2" max="-2" attributes="0"/>
+ <EmptySpace max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ </Layout>
+ <SubComponents>
+ <Component class="javax.swing.JProgressBar" name="m_progress">
+ <Properties>
+ <Property name="indeterminate" type="boolean" value="true"/>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ </Properties>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Component class="javax.swing.JButton" name="m_executeButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" value="Execute"/>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[100, 23]"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="executeButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JButton" name="m_allButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" value="Select All"/>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[100, 23]"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Container class="javax.swing.JScrollPane" name="m_suiteScroll">
+ <Properties>
+ <Property name="autoscrolls" type="boolean" value="true"/>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JList" name="m_suiteList">
+ <Properties>
+ <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+ <Connection code="new TestListModel()" type="code"/>
+ </Property>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ </Properties>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Container class="javax.swing.JScrollPane" name="m_resultScroll">
+ <Properties>
+ <Property name="verticalScrollBarPolicy" type="int" value="22"/>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JTable" name="m_resultTable">
+ <Properties>
+ <Property name="autoCreateRowSorter" type="boolean" value="true"/>
+ <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+ <Font name="Tahoma" size="10" style="0"/>
+ </Property>
+ <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+ <Connection code="new ResultTableModel()" type="code"/>
+ </Property>
+ <Property name="autoResizeMode" type="int" value="4"/>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="m_resultTableMouseClicked"/>
+ </Events>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Component class="javax.swing.JLabel" name="m_executedResults">
+ <Properties>
+ <Property name="text" type="java.lang.String" value="aaaaaaaaaaaaaaa"/>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="null"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JTextField" name="txtSearchTest">
+ </Component>
+ <Component class="javax.swing.JButton" name="btnSearch">
+ <Properties>
+ <Property name="text" type="java.lang.String" value="Search"/>
+ <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[90, 23]"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[100, 23]"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSearchActionPerformed"/>
+ </Events>
+ </Component>
+ </SubComponents>
+</Form>
diff --git a/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java
new file mode 100644
index 0000000..ed5133d
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java
@@ -0,0 +1,543 @@
+package org.apache.felix.ipojo.junit4osgi.command;
+/*
+ * 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.
+ */
+
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestResult;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+import javax.swing.*;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Swing Runner for Junit4Osgi.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SwingRunner extends javax.swing.JFrame implements BundleListener {
+
+ /**
+ * UUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Bundle context (to register the bundle listener).
+ */
+ private BundleContext m_context;
+
+ /**
+ * OSGi Junit Runner Service.
+ */
+ private OSGiJunitRunner m_runner;
+
+ /**
+ * State variable describing if we are executing tests.
+ */
+ private boolean m_running = false;
+
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton btnSearch;
+ private javax.swing.JButton m_allButton;
+ private javax.swing.JButton m_executeButton;
+ private javax.swing.JLabel m_executedResults;
+ private javax.swing.JScrollPane m_message;
+ private javax.swing.JTextArea m_messageArea;
+ private javax.swing.JButton m_ok;
+ private javax.swing.JProgressBar m_progress;
+ private javax.swing.JDialog m_resultDialog;
+ private javax.swing.JScrollPane m_resultScroll;
+ private javax.swing.JTable m_resultTable;
+ private javax.swing.JPanel m_statusBar;
+ private javax.swing.JList m_suiteList;
+ private javax.swing.JScrollPane m_suiteScroll;
+ private javax.swing.JTextField txtSearchTest;
+ // End of variables declaration//GEN-END:variables
+
+
+ public SwingRunner(BundleContext bc) {
+ m_running = false;
+ m_context = bc;
+ }
+
+
+ private void internalInitComponents() {
+ initComponents();
+ }
+
+
+
+ /**
+ * Start method.
+ */
+ public void start() {
+ internalInitComponents();
+ setVisible(true);
+ m_resultDialog.setVisible(false);
+ refreshSuites();
+ m_context.addBundleListener(this);
+ m_executedResults.setText(" \t No executed tests");
+ m_progress.setIndeterminate(false);
+ m_progress.setMaximum(100);
+ m_progress.setValue(100);
+
+ TableColumn column = null;
+ for (int i = 0; i < m_resultTable.getColumnCount(); i++) {
+ column = m_resultTable.getColumnModel().getColumn(i);
+ if (i == 0) {
+ column.setPreferredWidth(350); // first column is bigger
+ } else {
+ column.setPreferredWidth(50);
+ column.setCellRenderer(new ResultCellRenderer());
+ }
+ }
+ }
+
+
+
+ /**
+ * Stop method.
+ */
+ public void stop() {
+ m_context.removeBundleListener(this);
+ dispose();
+ }
+
+
+ /**
+ * Refresh the list of available test suites.
+ */
+ @SuppressWarnings("unchecked")
+ private void refreshSuites() {
+
+ String textToSearch = txtSearchTest.getText();
+ List<Test> tests = m_runner.getTests();
+
+ TestListModel lm = (TestListModel) m_suiteList.getModel();
+ lm.clear();
+
+ for (Test test : tests) {
+ String testName = test.toString();
+ if (textToSearch != null && !textToSearch.trim().equals("")) {
+ if (testName.toLowerCase().indexOf(textToSearch.toLowerCase()) != -1) {
+
+ lm.addTest(test);
+ }
+ } else {
+ // found all
+ lm.addTest(test);
+
+ }
+ }
+
+ //getInstanceManager().onExit(this, "refreshSuites", null);
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ m_resultDialog = new javax.swing.JDialog();
+ m_message = new javax.swing.JScrollPane();
+ m_messageArea = new javax.swing.JTextArea();
+ m_ok = new javax.swing.JButton();
+ m_statusBar = new javax.swing.JPanel();
+ m_progress = new javax.swing.JProgressBar();
+ m_executeButton = new javax.swing.JButton();
+ m_allButton = new javax.swing.JButton();
+ m_suiteScroll = new javax.swing.JScrollPane();
+ m_suiteList = new javax.swing.JList();
+ m_resultScroll = new javax.swing.JScrollPane();
+ m_resultTable = new javax.swing.JTable();
+ m_executedResults = new javax.swing.JLabel();
+ txtSearchTest = new javax.swing.JTextField();
+ btnSearch = new javax.swing.JButton();
+
+ m_resultDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+ m_resultDialog.setMinimumSize(new java.awt.Dimension(1024, 600));
+ m_resultDialog.addWindowListener(new java.awt.event.WindowAdapter() {
+ public void windowClosed(java.awt.event.WindowEvent evt) {
+ onDialogClosed(evt);
+ }
+
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ onDialogClosed(evt);
+ }
+ });
+
+ m_message.setBorder(null);
+ m_message.setMinimumSize(new java.awt.Dimension(300, 202));
+ m_message.setPreferredSize(new java.awt.Dimension(300, 202));
+
+ m_messageArea.setBackground(javax.swing.UIManager.getDefaults().getColor("Panel.background"));
+ m_messageArea.setColumns(20);
+ m_messageArea.setEditable(false);
+ m_messageArea.setLineWrap(true);
+ m_messageArea.setRows(5);
+ m_messageArea.setWrapStyleWord(true);
+ m_messageArea.setMinimumSize(new java.awt.Dimension(300, 250));
+ m_messageArea.setPreferredSize(new java.awt.Dimension(250, 200));
+ m_message.setViewportView(m_messageArea);
+
+ m_resultDialog.getContentPane().add(m_message, java.awt.BorderLayout.CENTER);
+
+ m_ok.setText("Ok");
+ m_ok.setPreferredSize(new java.awt.Dimension(120, 23));
+ m_ok.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ okActionPerformed(evt);
+ }
+ });
+ m_resultDialog.getContentPane().add(m_ok, java.awt.BorderLayout.SOUTH);
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setTitle("Junit Runner");
+ setMinimumSize(null);
+
+ m_progress.setIndeterminate(true);
+ m_progress.setMinimumSize(null);
+ m_progress.setPreferredSize(null);
+
+ javax.swing.GroupLayout m_statusBarLayout = new javax.swing.GroupLayout(m_statusBar);
+ m_statusBar.setLayout(m_statusBarLayout);
+ m_statusBarLayout.setHorizontalGroup(
+ m_statusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(m_progress, javax.swing.GroupLayout.DEFAULT_SIZE, 466, Short.MAX_VALUE)
+ );
+ m_statusBarLayout.setVerticalGroup(
+ m_statusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(m_statusBarLayout.createSequentialGroup()
+ .addComponent(m_progress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+
+ m_executeButton.setText("Execute");
+ m_executeButton.setMaximumSize(new java.awt.Dimension(90, 23));
+ m_executeButton.setMinimumSize(new java.awt.Dimension(90, 23));
+ m_executeButton.setPreferredSize(new java.awt.Dimension(100, 23));
+ m_executeButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ executeButtonActionPerformed(evt);
+ }
+ });
+
+ m_allButton.setText("Select All");
+ m_allButton.setMaximumSize(new java.awt.Dimension(90, 23));
+ m_allButton.setMinimumSize(new java.awt.Dimension(90, 23));
+ m_allButton.setPreferredSize(new java.awt.Dimension(100, 23));
+ m_allButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ allButtonActionPerformed(evt);
+ }
+ });
+
+ m_suiteScroll.setAutoscrolls(true);
+
+ m_suiteList.setModel(new TestListModel());
+ m_suiteList.setMaximumSize(null);
+ m_suiteList.setMinimumSize(null);
+ m_suiteList.setPreferredSize(null);
+ m_suiteScroll.setViewportView(m_suiteList);
+
+ m_resultScroll.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
+
+ m_resultTable.setAutoCreateRowSorter(true);
+ m_resultTable.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
+ m_resultTable.setModel(new ResultTableModel());
+ m_resultTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
+ m_resultTable.setMaximumSize(null);
+ m_resultTable.setMinimumSize(null);
+ m_resultTable.setPreferredSize(null);
+ m_resultTable.addMouseListener(new java.awt.event.MouseAdapter() {
+ public void mouseClicked(java.awt.event.MouseEvent evt) {
+ resultTableMouseClicked(evt);
+ }
+ });
+ m_resultScroll.setViewportView(m_resultTable);
+
+ m_executedResults.setText("aaaaaaaaaaaaaaa");
+ m_executedResults.setPreferredSize(null);
+
+ btnSearch.setText("Search");
+ btnSearch.setMaximumSize(new java.awt.Dimension(90, 23));
+ btnSearch.setMinimumSize(new java.awt.Dimension(90, 23));
+ btnSearch.setPreferredSize(new java.awt.Dimension(100, 23));
+ btnSearch.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnSearchActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(m_resultScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 598, Short.MAX_VALUE)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(m_statusBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(m_executedResults, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(txtSearchTest, javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(m_suiteScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 492, Short.MAX_VALUE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(m_executeButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(m_allButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(btnSearch, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(txtSearchTest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(btnSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(m_allButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(m_executeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(m_suiteScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 152, Short.MAX_VALUE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(m_resultScroll, javax.swing.GroupLayout.PREFERRED_SIZE, 415, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(m_executedResults, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(m_statusBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ );
+
+ pack();
+ }// </editor-fold>//GEN-END:initComponents
+
+
+ /**
+ * Execute button action.
+ *
+ * @param evt : event.
+ */
+ private void executeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_executeButtonActionPerformed
+ if (m_running) {
+ return;
+ }
+ // Collect selected test.
+ int[] indices = m_suiteList.getSelectedIndices();
+ List<Test> list = new ArrayList<Test>(indices.length);
+ TestListModel model = (TestListModel) m_suiteList.getModel();
+ for (int i = 0; i < indices.length; i++) {
+ list.add(model.getTestElementAt(indices[i]));
+ }
+ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ executeTest(list);
+ }//GEN-LAST:event_m_executeButtonActionPerformed
+
+ /**
+ * All button action.
+ *
+ * @param evt : event.
+ */
+ private void allButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_allButtonActionPerformed
+ int max = m_suiteList.getModel().getSize();
+ int[] indices = new int[max];
+ for (int i = 0; i < max; i++) {
+ indices[i] = i;
+ }
+ m_suiteList.setSelectedIndices(indices);
+ }//GEN-LAST:event_m_allButtonActionPerformed
+
+ /**
+ * Listener on table click.
+ *
+ * @param evt : event.
+ */
+ private void resultTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_m_resultTableMouseClicked
+ Point p = evt.getPoint();
+ int row = m_resultTable.rowAtPoint(p);
+ int col = m_resultTable.columnAtPoint(p);
+ ResultTableModel model = (ResultTableModel) m_resultTable.getModel();
+ String message = model.getMessage(row, col);
+ if (message != null) {
+ setEnabled(false);
+ m_resultDialog.setTitle("Test Report");
+ m_messageArea.setText(message);
+ m_resultDialog.setVisible(true);
+ }
+ }//GEN-LAST:event_m_resultTableMouseClicked
+
+ /**
+ * Ok button action.
+ *
+ * @param evt : event.
+ */
+ private void okActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_okActionPerformed
+ m_resultDialog.setVisible(false);
+ setEnabled(true);
+ }//GEN-LAST:event_m_okActionPerformed
+
+ /**
+ * Listener when the test report is closed.
+ *
+ * @param evt : event.
+ */
+ private void onDialogClosed(java.awt.event.WindowEvent evt) {
+ m_resultDialog.setVisible(false);
+ setEnabled(true);
+ }
+
+
+ private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {
+ refreshSuites();
+
+ }
+
+ /**
+ * Execute method.
+ *
+ * @param list : list of test to execute.
+ */
+ private void executeTest(final List<Test> list) {
+ Runnable thread = new Runnable() {
+ public void run() {
+ ResultTableModel model = (ResultTableModel) m_resultTable.getModel();
+ m_running = true;
+ m_executeButton.setText("Running...");
+ m_progress.setIndeterminate(true);
+ model.clear();
+ for (int i = 0; i < list.size(); i++) {
+ TestResult tr = new TestResult();
+ tr.addListener(new MyTestListener());
+ list.get(i).run(tr);
+ }
+ m_running = false;
+ m_progress.setIndeterminate(false);
+ m_progress.setMaximum(100);
+ m_progress.setValue(100);
+ m_executeButton.setText("Execute");
+ computeExecutedTest();
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ };
+ new Thread(thread).start();
+ }
+
+ /**
+ * Compute executed tests.
+ * (Status bar message)
+ */
+ private void computeExecutedTest() {
+ ResultTableModel results = (ResultTableModel) m_resultTable.getModel();
+ String m = " \t ";
+ m += results.getTestCount() + " tests executed / ";
+ m += results.getSucess() + " success / ";
+ m += results.getFailures() + " failures / ";
+ m += results.getErrors() + " errors ";
+ m_executedResults.setText(m);
+ }
+
+ private class MyTestListener implements junit.framework.TestListener {
+ /**
+ * Table model.
+ */
+ ResultTableModel m_model = (ResultTableModel) m_resultTable.getModel();
+
+ /**
+ * Add an error.
+ *
+ * @param arg0 : test which throws an error.
+ * @param arg1 : thrown exception.
+ * @see junit.framework.TestListener#addError(junit.framework.Test, Throwable)
+ */
+ public void addError(Test arg0, Throwable arg1) {
+ m_model.addTest(arg0, arg1);
+ adjustScroll();
+ }
+
+ /**
+ * Add a failure.
+ *
+ * @param arg0 : failing test.
+ * @param arg1 : thrown failure.
+ * @see junit.framework.TestListener#addError(junit.framework.Test, Throwable)
+ */
+ public void addFailure(Test arg0, AssertionFailedError arg1) {
+ m_model.addTest(arg0, arg1);
+ adjustScroll();
+ }
+
+ /**
+ * End of a test.
+ *
+ * @param arg0 : test.
+ * @see junit.framework.TestListener#endTest(junit.framework.Test)
+ */
+ public void endTest(Test arg0) {
+ m_model.addTest(arg0);
+ adjustScroll();
+ }
+
+ /**
+ * Start of a test.
+ *
+ * @param arg0 : test.
+ * @see junit.framework.TestListener#startTest(junit.framework.Test)
+ */
+ public void startTest(Test arg0) {
+ // Nothing to do here.
+ }
+
+ /**
+ * Adjust the scrolling bar of the result table.
+ */
+ private void adjustScroll() {
+ JScrollBar bar = m_resultScroll.getVerticalScrollBar();
+ if ((bar != null) && (bar.isVisible())) {
+ bar.setValue(Integer.MAX_VALUE);
+ }
+ }
+
+ }
+
+
+ public void bundleChanged(BundleEvent bundleevent) {
+ refreshSuites();
+
+ }
+
+}
\ No newline at end of file
diff --git a/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.java b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.java
new file mode 100644
index 0000000..3232dad
--- /dev/null
+++ b/ipojo/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.java
@@ -0,0 +1,129 @@
+/*
+ * 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.junit4osgi.command;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.AbstractListModel;
+import junit.framework.Test;
+
+/**
+ * Test Suite list model.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestListModel extends AbstractListModel {
+
+ /**
+ * Id.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * List of {@link TestRecord}.
+ */
+ private List<TestRecord> m_list = new ArrayList<TestRecord>();
+
+ /**
+ * Gets the element placed at the given index.
+ * @param index the index
+ * @return the element placed at the given index
+ * or <code>null</code> if no element at this index
+ * @see javax.swing.ListModel#getElementAt(int)
+ */
+ public Object getElementAt(int index) {
+ if (index >= m_list.size()) {
+ return null;
+ } else {
+ return m_list.get(index).m_name;
+ }
+ }
+
+ /**
+ * Gets the test object placed at the given index.
+ * @param index the index
+ * @return the test object placed at the given index
+ */
+ public Test getTestElementAt(int index) {
+ return m_list.get(index).m_test;
+ }
+
+ /**
+ * Adds a test.
+ * @param test the test to add
+ */
+ public void addTest(Test test) {
+ synchronized (this) {
+ TestRecord tr = new TestRecord();
+ tr.m_test = test;
+ tr.m_name = test.toString();
+ m_list.add(tr);
+ }
+ fireContentsChanged(this, m_list.size() - 1, m_list.size() - 1);
+ }
+
+ /**
+ * Removes a test.
+ * @param test the test to remove
+ */
+ public void removeTest(Test test) {
+ int index = 1;
+ synchronized (this) {
+ for (TestRecord t : m_list) {
+ if (t.m_test.equals(test)) {
+ index = m_list.indexOf(t);
+ m_list.remove(t);
+ return;
+ }
+ }
+ }
+
+ if (index != -1) {
+ fireContentsChanged(this, index, index);
+ }
+ }
+
+ /**
+ * Clears the list.
+ */
+ public void clear() {
+ m_list.clear();
+ }
+
+ private class TestRecord {
+ /**
+ * The test.
+ */
+ public Test m_test;
+
+ /**
+ * The test name.
+ */
+ public String m_name;
+ }
+
+ /**
+ * Gets the list size.
+ * @return the list size.
+ * @see javax.swing.ListModel#getSize()
+ */
+ public int getSize() {
+ return m_list.size();
+ }
+
+}
diff --git a/ipojo/manipulator/annotations/changelog.txt b/ipojo/manipulator/annotations/changelog.txt
new file mode 100644
index 0000000..fec2dea
--- /dev/null
+++ b/ipojo/manipulator/annotations/changelog.txt
@@ -0,0 +1,225 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3742] - Implementing class fails to load unless super interface's (interface extended by implemented interface) package is imported.
+ * [FELIX-3789] - Deadlock due to synchronization on INSTANCE_NAME
+ * [FELIX-3819] - The export directive of iPOJO is wrong
+
+Changes from the 1.8.2 to 1.8.4
+--------------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3500] - InstanceManager concurrency issue: "A methodID cannot be associated with a method from the POJO class"
+ * [FELIX-3501] - IPojo FactoryStateListener doesn't get notified while stopping factory
+ * [FELIX-3545] - Memory leak when unregistering a component used by an aggregate dependency with an unbind callback
+ * [FELIX-3548] - Concurrent access during startup
+ * [FELIX-3567] - iPOJO Configuration Handler should not reuse the dictionary object from the configuration admin
+ * [FELIX-3576] - iPOJO fails when using constructor injection and expecting BundleContext in ctor
+ * [FELIX-3599] - Problem with 'subservice action="instantiate"' in ipojo composite
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+ * [FELIX-3672] - Potential Concurrent Modification Exception when a bundle is stopped
+
+** Improvement
+ * [FELIX-3560] - Extensions to IPojo's Factory and ComponentInstance documentation for custom handlers
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+** Improvement
+ * [FELIX-3380] - minor javadoc corrections in @Temporal annotation
+
+Changes from the 1.6.4 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2568] - Rename Transactionnal to Transactional
+
+** Improvement
+ * [FELIX-1428] - Constructor injection of Configuration properties
+ * [FELIX-2620] - Change iPojo annotation parameters to follow java naming conventions
+ * [FELIX-2621] - Rename annotations to remove collisions
+ * [FELIX-2622] - Support static service properties that are not mirrored into fields
+ * [FELIX-2624] - Support multiple whiteboards using annotations
+ * [FELIX-2630] - Rename @Component attributes to follow the java naming conventions
+ * [FELIX-2631] - Rename @Publisher and @Subscriber attributes to follow the java naming conventions
+ * [FELIX-2633] - Rename JMX annotations
+ * [FELIX-2634] - Rename the @Publisher annotation into @Publishes annotation to avoid collision
+ * [FELIX-2666] - Rename the temporal handler annotation to avoid collision
+ * [FELIX-2742] - Constructor injection of service dependencies
+
+Changes from the 1.6.2 to 1.6.4
+-------------------------------
+** Improvement
+ * [FELIX-2420] - Enum support for @Property annotation
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Improvement
+ * [FELIX-2296] - Access to ServiceReference in iPOJO service.
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1557] - Cosmetic change of the Bundle-Name and Bundle-SymbolicName in iPOJO annotations.
+
+** Improvement
+ * [FELIX-1426] - Service injection with Dynamic Proxies
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+** New Feature
+ * [FELIX-2132] - Provides a way to control service exposition from the implementation class
+
+** Wish
+ * [FELIX-1940] - Add @Instance annotation to declare instances without metadata.xml
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1319] - Issue in the metadata overriding analysis in iPOJO annotations
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-825] - Provide annotation for iPojo JMX Handler
+ * [FELIX-834] - Provide Annotations for the extender, whiteboard and event admin handlers
+
+** Bug
+ * [FELIX-867] - iPOJO @ServiceProperty can target method
+ * [FELIX-868] - iPOJO @Component don't support factory methods
+
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * [FELIX-627] - Temporal dependency annotation
+
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/manipulator/annotations/pom.xml b/ipojo/manipulator/annotations/pom.xml
new file mode 100644
index 0000000..636e203
--- /dev/null
+++ b/ipojo/manipulator/annotations/pom.xml
@@ -0,0 +1,51 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Annotations</name>
+
+ <description>
+ iPOJO Annotation pack. contained annotations are used to define iPOJO component type.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-gettingstarted/how-to-use-ipojo-annotations.html
+ </url>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/manipulator/annotations/src/main/appended-resources/NOTICE b/ipojo/manipulator/annotations/src/main/appended-resources/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/appended-resources/NOTICE
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Bind.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Bind.java
new file mode 100644
index 0000000..51042e9
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Bind.java
@@ -0,0 +1,87 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Comparator;
+
+/**
+ * This annotation declares a bind method.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Bind {
+
+ /**
+ * Set the dependency filter.
+ * Default : no filter
+ */
+ String filter() default "";
+
+ /**
+ * Set if the dependency is an aggregate dependency.
+ * Default : false
+ */
+ boolean aggregate() default false;
+
+ /**
+ * Set if the dependency is optional.
+ * Default : false
+ */
+ boolean optional() default false;
+
+ /**
+ * Set the required specification.
+ * Default : no specification, will be deduced.
+ */
+ Class specification() default Object.class;
+
+ /**
+ * Set the dependency id.
+ * Default : empty
+ */
+ String id() default "";
+
+ /**
+ * Set the binding policy.
+ * Acceptable policies are dynamic, static and dynamic-priority.
+ * Default: dynamic.
+ */
+ BindingPolicy policy() default BindingPolicy.DYNAMIC;
+
+ /**
+ * Set the comparator.
+ * The indicated class must implement {@link Comparator}
+ */
+ Class<? extends Comparator> comparator() default Comparator.class;
+
+ /**
+ * Set the from attribute.
+ */
+ String from() default "";
+
+ /**
+ * Set to true if the service dependency is injected
+ * as a proxy.
+ * Default: true
+ */
+ boolean proxy() default true;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/BindingPolicy.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/BindingPolicy.java
new file mode 100644
index 0000000..6b86701
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/BindingPolicy.java
@@ -0,0 +1,29 @@
+/*
+ * 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.annotations;
+
+/**
+* Binding policies supported by iPOJO.
+*/
+public enum BindingPolicy {
+ DYNAMIC,
+ STATIC,
+ DYNAMIC_PRIORITY;
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Component.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Component.java
new file mode 100644
index 0000000..a38245d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Component.java
@@ -0,0 +1,178 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Declares a component type (needed to create instances of the component).
+ * This annotation is mandatory to declares an iPOJO component.
+ *
+ * Its usual to find it on top of class definition:
+ * <pre>
+ * {@code @Component}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ *
+ * But, it is also possible to have it associated to a
+ * {@linkplain org.apache.felix.ipojo.annotations.Stereotype stereotyped} annotation definition:
+ * <pre>
+ * {@code @Component}
+ * {@linkplain org.apache.felix.ipojo.annotations.Instantiate @Instantiate}
+ * {@linkplain org.apache.felix.ipojo.annotations.Stereotype @Stereotype}
+ * public @interface AutoInstantiatedComponent {
+ * // ...
+ * }
+ * </pre>
+ *
+ * <h2>See also</h2>
+ * <ul>
+ * <li><a href="http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/ipojo-advanced-topics/how-to-use-ipojo-factories.html">Use iPOJO Factories</a></li>
+ * </ul>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Component {
+
+ /**
+ * Set if the component type is public.
+ * @see #publicFactory()
+ * @deprecated renamed to publicFactory.
+ */
+ boolean public_factory() default true;
+
+ /**
+ * Set if the component type is public or private (defaults to public).
+ * A private factory does not expose a {@code Factory} service.
+ * Only instances declared in the same bundle are created.
+ * <pre>
+ * {@code @Component(publicFactory = false)}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * Default: {@literal true}
+ */
+ boolean publicFactory() default true;
+
+ /**
+ * Set the component type name.
+ * <pre>
+ * {@code @Component(name = "my-component")}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * Default : implementation class name.
+ */
+ String name() default "";
+
+ /**
+ * Enable / Disable the architecture exposition (no {@code Architecture}
+ * service will be exposed for component's instances).
+ * <pre>
+ * {@code @Component(architecture = false)}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * Default : {@literal true}
+ */
+ boolean architecture() default true;
+
+ /**
+ * Set if the component is immediate.
+ * By default, iPOJO tries to be as lazy as possible and will create the POJO instance at the last possible time.
+ * Notice this setting is only effective when the component provides a service ({@linkplain org.apache.felix.ipojo.annotations.Provides @Provides}).
+ * <pre>
+ * {@code @Component(immediate = true)}
+ * {@linkplain org.apache.felix.ipojo.annotations.Provides @Provides}
+ * public class MyComponent implements MyService {
+ * // ...
+ * }
+ * </pre>
+ * Default : {@literal false}
+ */
+ boolean immediate() default false;
+
+ /**
+ * Enable or disable the configuration propagation to service properties.
+ * <pre>
+ * {@code @Component(propagation = false)}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * default: {@literal true}
+ */
+ boolean propagation() default true;
+
+ /**
+ * Set the Managed Service PID for Configuration Admin.
+ * default no PID (i.e. the managed service will not be exposed).
+ * <pre>
+ * {@code @Component(managedservice = "my.Pid")}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ */
+ String managedservice() default "";
+
+ /**
+ * Set the factory-method, if the pojo has to be created
+ * from a static method. The specified method must be a static
+ * method and return a pojo object.
+ * By default, iPOJO uses the 'regular' constructor.
+ * @see #factoryMethod()
+ * @deprecated now is called <tt>factoryMethod</tt>.
+ */
+ String factory_method() default "";
+
+ /**
+ * Set the factory-method, if the pojo has to be created
+ * from a static method. The specified method must be a static
+ * method and return a pojo object.
+ * By default, iPOJO uses the 'regular' constructor.
+ * <pre>
+ * {@code @Component(factoryMethod = "createInstance")}
+ * public class MyComponent {
+ * // ...
+ * public static MyComponent createInstance() {
+ * return new MyComponent("some static configuration");
+ * }
+ * }
+ * </pre>
+ */
+ String factoryMethod() default "";
+
+ /**
+ * Set the version of the component type.
+ * <pre>
+ * {@code @Component(version = "1.3")}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ */
+ String version() default "";
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Context.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Context.java
new file mode 100644
index 0000000..383583d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Context.java
@@ -0,0 +1,54 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Injects the bundle context object.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER, ElementType.FIELD})
+public @interface Context {
+
+ /**
+ * Sets which bundle context object needs to be injected.
+ */
+ public Source value() default Source.COMPONENT;
+
+ /**
+ * Lists the different injectable bundle context.
+ */
+ public enum Source {
+ /**
+ * The bundle context from the bundle declaring the component. Generally,
+ * it's the bundle containing the implementation class.
+ */
+ COMPONENT,
+
+ /**
+ * The bundle context from the bundle declaring the instance.
+ */
+ INSTANCE
+ }
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java
new file mode 100644
index 0000000..babcf01
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java
@@ -0,0 +1,52 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a <a href="http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/instance-vs-service-controller.html">lifecycle controller</a>.
+ *
+ * <pre>
+ * {@code @Component}
+ * public class MyComponent {
+ * // ...
+ * {@code @Controller}
+ * private boolean controller;
+ *
+ * public void aMethod() {
+ * // Invalidate the instance
+ * controller = false;
+ * }
+ *
+ * public void anotherMethod() {
+ * // Validate the instance again
+ * controller = true;
+ * }
+ * }
+ * </pre>
+
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface Controller {
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Handler.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Handler.java
new file mode 100644
index 0000000..b3fa777
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Handler.java
@@ -0,0 +1,63 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a handler.
+ * This annotation is mandatory to declares an iPOJO handler.
+ * <pre>
+ * {@code @Handler}(
+ * name = "my-handler",
+ * namespace = "com.acme.foo"
+ * )
+ * public class MyHandler extends PrimitiveHandler {
+ * // ...
+ * }
+ * </pre>
+
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Handler {
+
+ /**
+ * Name of the handler (required).
+ */
+ String name();
+
+ /**
+ * Namespace of the handler (required).
+ */
+ String namespace();
+
+ /**
+ * Start-level of the handler.
+ * Default: 1.
+ */
+ int level() default 1;
+
+ /**
+ * Enable / Disable the architecture exposition.
+ * Default : {@literal false}
+ */
+ boolean architecture() default false;
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerBinding.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerBinding.java
new file mode 100644
index 0000000..f18f4c4
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerBinding.java
@@ -0,0 +1,85 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A @{@link HandlerBinding} bind its annotated type to a given handler.
+ *
+ * The handler name is specified as parameter using the {@literal 'namespace:name'} format (qualified name).
+ *
+ * <pre>
+ * // Namespace and name will be inferred from the annotation's package name.
+ * @HandlerBinding()
+ * public @interface Foo {}
+ *
+ * // No namespace declared, default will be used ('org.apache.felix.ipojo')
+ * @HandlerBinding("foo")
+ * public @interface Foo {}
+ *
+ * // Namespace will be 'com.acme' and name: 'foo'
+ * @HandlerBinding("com.acme:foo")
+ * public @interface Foo {}
+ *
+ * // Provided namespace and value (for the name) will be used
+ * @HandlerBinding(namespace = "com.acme", value = "foo")
+ * public @interface Foo {}
+ * </pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface HandlerBinding {
+ String DEFAULT = "#";
+
+ /**
+ * Defines the handler's namespace. Must be used in correlation with the {@literal value} attribute.
+ * <pre>
+ * @HandlerBinding(namespace = "com.acme", value = "foo")
+ * public @interface Foo {}
+ * </pre>
+ */
+ String namespace() default DEFAULT;
+
+ /**
+ * When used <b>without</b> the {@literal namespace} attribute, defines both the namespace + name
+ * of a handler in a short notation (if no namespace can be found in the parameter - no ':' separator - fallback
+ * on iPOJO's default namespace):
+ *
+ * <pre>
+ * @HandlerBinding("com.acme:foo")
+ * public @interface Foo {}
+ * </pre>
+ *
+ * When used <b>with</b> the {@literal namespace} attribute, holds the name of the handler (without
+ * its namespace part):
+ *
+ * <pre>
+ * @HandlerBinding(namesapce = "com.acme", value = "foo")
+ * public @interface Foo {}
+ * </pre>
+ */
+ String value() default DEFAULT;
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerDeclaration.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerDeclaration.java
new file mode 100644
index 0000000..1191d47
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/HandlerDeclaration.java
@@ -0,0 +1,44 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to configure a handler through XML (as in {@literal metadata.xml}).
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @HandlerDeclaration("<ns:my-handler attribute='value' xmlns:ns='http://www.acme.com/ipojo/ns'/>")}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface HandlerDeclaration {
+
+ /**
+ * The content of this attribute represents the XML
+ * that would be used in the metadata.xml.
+ * It must be a root XML Element, namespaces are allowed and so for child elements.
+ */
+ String value();
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Ignore.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Ignore.java
new file mode 100644
index 0000000..ceb4171
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Ignore.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A @{@link Ignore} annotation mark its annotated type to be ignored by the iPOJO manipulator.
+ * This is handy when the annotation could be recognized as a "custom annotation handler" (contains {@literal ".ipojo."}
+ * or {@literal ".handler."} in its package name) but in fact is not a handler annotation at all.
+ *
+ * <pre>
+ * package com.acme.ipojo.handler;
+ * @Ignore
+ * public @interface Foo {}
+ * </pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface Ignore {}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Instantiate.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Instantiate.java
new file mode 100644
index 0000000..87d9201
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Instantiate.java
@@ -0,0 +1,55 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to create an 'empty' instance of the
+ * current component type.
+ *
+ * Notice that all mandatory properties should have a default value, otherwise
+ * configuration is declared unacceptable and the instance creation fails.
+ *
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @Instantiate}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Instantiate {
+
+ /**
+ * Optional attribute to set the instance name.
+ * Default: unique generated name
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @Instantiate("my-default-component")}
+ * public class MyComponent {
+ * // ...
+ * }
+ * </pre>
+ */
+ String name() default "";
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Invalidate.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Invalidate.java
new file mode 100644
index 0000000..0dfac8c
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Invalidate.java
@@ -0,0 +1,38 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares an invalidate callback.
+ *
+ * <pre>
+ * {@code @Invalidate}
+ * public void stop() {
+ * // Code executed when instances are becoming invalid
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Invalidate {
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Modified.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Modified.java
new file mode 100644
index 0000000..ea8bd5a
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Modified.java
@@ -0,0 +1,81 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Comparator;
+
+/**
+ * This annotation declares a modify method.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Modified {
+
+ /**
+ * Set the dependency filter.
+ * Default : no filter
+ */
+ String filter() default "";
+
+ /**
+ * Set if the dependency is an aggregate dependency.
+ * Default : false
+ */
+ boolean aggregate() default false;
+
+
+ /**
+ * Set if the dependency is optional.
+ * Default : false
+ */
+ boolean optional() default false;
+
+ /**
+ * Set the required specification.
+ * Default : empty (try to discover).
+ */
+ String specification() default "";
+
+ /**
+ * Set the dependency id.
+ * Default : empty.
+ */
+ String id() default "";
+
+ /**
+ * Set the binding policy.
+ * Acceptable policies are dynamic, static and dynamic-priority.
+ * Default: dynamic.
+ */
+ BindingPolicy policy() default BindingPolicy.DYNAMIC;
+
+ /**
+ * Set the comparator.
+ * The indicated class must implement {@link Comparator}
+ */
+ Class<? extends Comparator> comparator() default Comparator.class;
+
+ /**
+ * Set the from attribute.
+ */
+ String from() default "";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostRegistration.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostRegistration.java
new file mode 100644
index 0000000..0319439
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostRegistration.java
@@ -0,0 +1,40 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+/**
+ * Declares a method to be <a href="http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/providing-osgi-services.html#being-notified-of-the-service-registration-and-unregistration">notified after service registration</a> is effective.
+ *
+ * <pre>
+ * {@code @PostRegistration}
+ * public void registered(ServiceReference<?> reference) {
+ * // Called after the service publication
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Provides
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface PostRegistration {
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostUnregistration.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostUnregistration.java
new file mode 100644
index 0000000..50f7040
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/PostUnregistration.java
@@ -0,0 +1,40 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+/**
+ * Declares a method to be <a href="http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/providing-osgi-services.html#being-notified-of-the-service-registration-and-unregistration">notified after service un-registration</a> is effective.
+ *
+ * <pre>
+ * {@code @PostUnregistration}
+ * public void unregistered(ServiceReference<?> reference) {
+ * // Called after the service un-publication
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Provides
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface PostUnregistration {
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Property.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Property.java
new file mode 100644
index 0000000..9af34cb
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Property.java
@@ -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.felix.ipojo.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a component property.
+ * It can target both fields and methods.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
+public @interface Property {
+
+ /**
+ * Set property name.
+ * Default : empty
+ */
+ String name() default "";
+
+ /**
+ * Set property value.
+ * Default : empty
+ */
+ String value() default "";
+
+ /**
+ * Is the property mandatory?
+ * Default: false
+ */
+ boolean mandatory() default false;
+
+ /**
+ * Is the property immutable?
+ * Default: false
+ */
+ boolean immutable() default false;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
new file mode 100644
index 0000000..d0f06ee
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
@@ -0,0 +1,92 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares that the component instances will provide a service.
+ *
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @Provides}
+ * public class MyComponent implements Service {
+ * // ...
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Provides {
+
+ /**
+ * Set the provided specifications.
+ * It can be used to force the exposed service to use an implementation class
+ * (not an interface) as specification.
+ * Default : all implemented interfaces
+ *
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @Provides(specifications = AbsComponent.class)}
+ * public class MyComponent extends AbsComponent {
+ * // ...
+ * }
+ * </pre>
+ */
+ Class[] specifications() default { };
+
+ /**
+ * Set the service object creation strategy.
+ * Multiple values are possible: {@literal SINGLETON}, {@literal SERVICE},
+ * {@literal METHOD}, {@literal INSTANCE} or the strategy fully qualified class name:
+ * <ul>
+ * <li>{@literal SINGLETON}: Default strategy</li>
+ * <li>{@literal SERVICE}: OSGi Service Factory style, 1 POJO instance per consumer bundle</li>
+ * <li>{@literal METHOD}: Delegates the creation to the factory-method of the component, method will be called every time the service reference is get.</li>
+ * <li>{@literal INSTANCE}: Creates one service object per requiring instance</li>
+ * <li>Any other value is interpreted as the qualified name of a {@code CreationStrategy} implementation</li>
+ * </ul>
+ */
+ String strategy() default "SINGLETON";
+
+ /**
+ * Allows adding static properties to the service.
+ * Nested properties are static service properties, so <b>must</b> contain the name,
+ * value and type as they are not attached to a field (cannot discover type through
+ * introspection).
+ * The array contains {@link StaticServiceProperty} elements.
+ * Default : No service properties
+
+ * <pre>
+ * {@linkplain org.apache.felix.ipojo.annotations.Component @Component}
+ * {@code @Provides}(
+ * properties = {
+ * {@code @StaticServiceProperty}(name = "size", type = "int", value = "5"),
+ * {@code @StaticServiceProperty}(name = "name", type = "java.lang.String", value = "OSGi")
+ * }
+ * )
+ * public class MyComponent implements Service {
+ * // ...
+ * }
+ * </pre>
+
+ */
+ StaticServiceProperty[] properties() default {};
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java
new file mode 100644
index 0000000..254016d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java
@@ -0,0 +1,112 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Target;
+import java.util.Comparator;
+
+/**
+ * This annotation declares a service requirement.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
+@Inherited
+public @interface Requires {
+
+ /**
+ * Set the LDAP filter of the dependency.
+ * Default : no filter
+ */
+ String filter() default "";
+
+ /**
+ * Set if the dependency is optional.
+ * Default : false
+ */
+ boolean optional() default false;
+
+ /**
+ * Set the dependency id.
+ * Default : empty
+ */
+ String id() default "";
+
+ /**
+ * Enable / Disable nullable pattern.
+ * Default : true
+ */
+ boolean nullable() default true;
+
+ /**
+ * Set the default-implementation to use if the dependency is optional,
+ * and no providers are available.
+ * The class must implement the required service interface.
+ * Default : no default-implementation
+ */
+ Class defaultimplementation() default Class.class;
+
+ /**
+ * Set the exception to throw when the service is not available. This attribute can only be used for optional
+ * dependencies. It must be a subclass of {@link RuntimeException}.
+ * Default: no exception.
+ */
+ Class<? extends RuntimeException> exception() default RuntimeException.class;
+
+ /**
+ * Set the binding policy.
+ * Acceptable policy are dynamic, static and dynamic-priority.
+ * Default: dynamic.
+ */
+ BindingPolicy policy() default BindingPolicy.DYNAMIC;
+
+ /**
+ * Set the comparator.
+ * The indicated class must implement {@link Comparator}
+ */
+ Class<?extends Comparator> comparator() default Comparator.class;
+
+ /**
+ * Set the from attribute.
+ */
+ String from() default "";
+
+ /**
+ * Set the required service specification.
+ * This attribute is required for Collection field.
+ */
+ Class specification() default Object.class;
+
+ /**
+ * Set to true if the service dependency is injected
+ * as a proxy.
+ * Default: true
+ */
+ boolean proxy() default true;
+
+
+ /**
+ * Set the time to wait before applying the 'no service available' action.
+ * This attribute is only valid for optional dependencies.
+ * The time is set in milliseconds.
+ * Default: no timeout
+ */
+ int timeout() default -1;
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceController.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceController.java
new file mode 100644
index 0000000..61e539e
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceController.java
@@ -0,0 +1,43 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a service controller.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface ServiceController {
+
+ /**
+ * Sets the initial value of the controller.
+ */
+ boolean value() default true;
+
+
+ /**
+ * Sets the targeted specification.
+ * If not set, target all specifications.
+ */
+ Class specification() default Object.class;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceProperty.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceProperty.java
new file mode 100644
index 0000000..5ce5f39
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/ServiceProperty.java
@@ -0,0 +1,57 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a service property.
+ * It can target both fields and methods.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface ServiceProperty {
+
+ /**
+ * Set the property name.
+ * Default : empty
+ */
+ String name() default "";
+
+ /**
+ * Set the property value.
+ * Default : empty
+ */
+ String value() default "";
+
+ /**
+ * Is the property mandatory?
+ * Default: false
+ */
+ boolean mandatory() default false;
+
+ /**
+ * Is the service property immutable ?
+ * An immutable property <b>MUST</b> have a value
+ * Default {@literal false}
+ */
+ boolean immutable() default false;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/StaticServiceProperty.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/StaticServiceProperty.java
new file mode 100644
index 0000000..969725d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/StaticServiceProperty.java
@@ -0,0 +1,61 @@
+/*
+ * 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.annotations;
+
+
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a static service property.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({})
+public @interface StaticServiceProperty {
+
+ /**
+ * Set the property name.
+ * This name is mandatory for static properties.
+ */
+ String name();
+
+ /**
+ * Set the property value.
+ * Default : empty
+ */
+ String value() default "";
+
+ /**
+ * Is the property mandatory?
+ * Default: false
+ */
+ boolean mandatory() default false;
+
+ /**
+ * Set the type.
+ * This value is required only for static properties.
+ */
+ String type();
+
+ /**
+ * Is the property immutable ?
+ * An immutable property <b>MUST</b> have a value
+ * Default: {@literal false}
+ */
+ boolean immutable() default false;
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Stereotype.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Stereotype.java
new file mode 100644
index 0000000..efb8369
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Stereotype.java
@@ -0,0 +1,72 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * In many systems, use of architectural patterns produces a set of recurring roles. A stereotype allows a
+ * framework developer to identify such a role and declare some common metadata for objects with that role
+ * in a central place.
+ *
+ * A stereotype is an annotation, annotated with {@literal @Stereotype}, that captures several other annotations.
+ *
+ * For example, the following stereotype defines a @PseudoSingletonComponent annotation, that will act,
+ * when applied on a component, just like if @Component and @Instantiate where directly applied on the target component.
+ * <pre>
+ *
+ * @Component
+ * @Instantiate
+ * @Stereotype
+ * @Target(TYPE)
+ * @Retention(CLASS)
+ * public @interface PseudoSingletonComponent {}
+ *
+ * </pre>
+ *
+ * Usage:
+ * <pre>
+ *
+ * @PseudoSingletonComponent
+ * public class HelloWorldComponent {
+ * // ...
+ * }
+ *
+ * </pre>
+ *
+ * Equivalent to:
+ * <pre>
+ *
+ * @Component
+ * @Instantiate
+ * public class HelloWorldComponent {
+ * // ...
+ * }
+ *
+ * </pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface Stereotype {
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Unbind.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Unbind.java
new file mode 100644
index 0000000..ae71620
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Unbind.java
@@ -0,0 +1,88 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Comparator;
+
+/**
+ * This annotation declares an unbind method.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Unbind {
+
+ /**
+ * Set the dependency filter.
+ * Default : no filter
+ */
+ String filter() default "";
+
+ /**
+ * Set if the dependency is an aggregate dependency.
+ * Default : false
+ */
+ boolean aggregate() default false;
+
+
+ /**
+ * Set if the dependency is optional.
+ * Default : false
+ */
+ boolean optional() default false;
+
+ /**
+ * Set the required specification.
+ * Default : empty (try to discover).
+ */
+ Class specification() default Object.class;
+
+ /**
+ * Set the dependency id.
+ * Default : empty.
+ */
+ String id() default "";
+
+ /**
+ * Set the binding policy.
+ * Acceptable policy are dynamic, static and dynamic-priority.
+ * Default: dynamic.
+ */
+ BindingPolicy policy() default BindingPolicy.DYNAMIC;
+
+ /**
+ * Set the comparator.
+ * The indicated class must implement {@link Comparator}
+ */
+ Class<? extends Comparator> comparator() default Comparator.class;
+
+ /**
+ * Set the from attribute.
+ */
+ String from() default "";
+
+ /**
+ * Set to true if the service dependency is injected
+ * as a proxy.
+ * Default: true
+ */
+ boolean proxy() default true;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Updated.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Updated.java
new file mode 100644
index 0000000..5fa9270
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Updated.java
@@ -0,0 +1,47 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares an updated callback.
+ * Updated callback are called after a <a href="http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/describing-components/configuration-handler.html#being-notified-when-a-reconfiguration-is-completed">reconfiguration</a>.
+ *
+ * Methods annotated with {@code @Updated} must have one of the 2 following signatures:
+ * <pre>
+ * {@code @Updated}
+ * public void updated() {
+ * // The instance was reconfigured
+ * }
+ * </pre>
+ *
+ * <pre>
+ * {@code @Updated}
+ * public void updated(Dictionary conf) {
+ * // The instance was reconfigured, conf is the new configuration.
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Updated {
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Validate.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Validate.java
new file mode 100644
index 0000000..3a6517e
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Validate.java
@@ -0,0 +1,38 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation declares a validate callback.
+ *
+ * <pre>
+ * {@code @Validate}
+ * public void start() {
+ * // Code executed when instances are becoming valid
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Validate {
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/extender/Extender.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/extender/Extender.java
new file mode 100644
index 0000000..587710a
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/extender/Extender.java
@@ -0,0 +1,49 @@
+/*
+ * 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.extender;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Extender pattern Handler annotation.
+ * Allows configuring an extender pattern.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Extender {
+
+ /**
+ * Sets the looked Manifest entry.
+ */
+ String extension();
+
+ /**
+ * Sets the on service arrival callback.
+ */
+ String onArrival();
+
+ /**
+ * Sets the on service departure callback.
+ */
+ String onDeparture();
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Requires.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Requires.java
new file mode 100644
index 0000000..3e9e03a
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Requires.java
@@ -0,0 +1,70 @@
+/*
+ * 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.handler.temporal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Temporal dependency annotation.
+ * Allows specifying a temporal dependency.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @deprecated replaced by {@link Temporal}
+ */
+@Target(ElementType.FIELD)
+@Deprecated
+public @interface Requires {
+
+ /**
+ * Set the LDAP filter of the dependency.
+ * Default : no filter
+ */
+ String filter() default "";
+
+ /**
+ * Timeout of the dependency.
+ * Default : true
+ */
+ long timeout() default 3000;
+
+ /**
+ * Set the on timeout action.
+ * Supports null, nullable, empty, and default-implementation.
+ * In this latter case, you must specify the qualified class name
+ * of the default-implementation (instead of default-implementation).
+ * Default: no action (i.e throws a runtime exception)
+ */
+ String onTimeout() default "";
+
+ /**
+ * Set the service specification (for Collection fields).
+ * This attribute is mandatory for Collections.
+ */
+ String specification() default "";
+
+ /**
+ * Inject a proxy instead of the real object.
+ * This allows passing this reference to collaborators.
+ * Default: false
+ */
+ boolean proxy() default false;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Temporal.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Temporal.java
new file mode 100644
index 0000000..52496a5
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handler/temporal/Temporal.java
@@ -0,0 +1,75 @@
+/*
+ * 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.handler.temporal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Temporal dependency annotation.
+ * Allows specifying a temporal dependency.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface Temporal {
+
+ /**
+ * Set the dependency id.
+ * Default: empty, will use the field name.
+ */
+ String id() default "";
+
+ /**
+ * Set the LDAP filter of the dependency.
+ * Default: no filter
+ */
+ String filter() default "";
+
+ /**
+ * Timeout of the dependency.
+ * Default: 3000 ms.
+ */
+ long timeout() default 3000;
+
+ /**
+ * Set the on timeout action.
+ * Supports null, nullable, empty, and default-implementation.
+ * In this latter case, you must specify the qualified class name
+ * of the default-implementation (instead of default-implementation).
+ * Default: no action (i.e throws a runtime exception)
+ */
+ String onTimeout() default "";
+
+ /**
+ * Set the service specification (for Collection fields).
+ * This attribute is mandatory for Collections.
+ */
+ String specification() default "";
+
+ /**
+ * Inject a proxy instead of the real object.
+ * This allows passing this reference to collaborators.
+ * Default: false
+ */
+ boolean proxy() default false;
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publisher.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publisher.java
new file mode 100644
index 0000000..466d6f0
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publisher.java
@@ -0,0 +1,69 @@
+/*
+ * 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.handlers.event;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+/**
+ * Event Admin Publisher handler.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @deprecated replaced by Publishes
+ */
+@Target(ElementType.FIELD)
+public @interface Publisher {
+
+ /**
+ * Sets the publisher name.
+ */
+ String name();
+
+ /**
+ * Sets topics on which event are sent.
+ * The topics are separated by a ',' such as in
+ * "foo, bar".
+ * Default : no topics (configured in the instance configuration)
+ */
+ String topics() default "";
+
+ /**
+ * Enables/Disables synchronous sending.
+ * Default : false (asynchronous)
+ */
+ boolean synchronous() default false;
+
+ /**
+ * Sets the data key in which the data is
+ * put.
+ * Default : user.data
+ * @deprecated replaced by dataKey
+ */
+ String data_key() default "user.data";
+
+ /**
+ * Sets the data key in which the data is
+ * put.
+ * Default : user.data
+ */
+ String dataKey() default "user.data";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publishes.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publishes.java
new file mode 100644
index 0000000..eea2f80
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Publishes.java
@@ -0,0 +1,60 @@
+/*
+ * 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.handlers.event;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+/**
+ * Event Admin Publisher handler.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface Publishes {
+
+ /**
+ * Sets the publisher name.
+ */
+ String name();
+
+ /**
+ * Sets topics on which event are sent.
+ * The topics are separated by a ',' such as in
+ * "foo, bar".
+ * Default : no topics (configured in the instance configuration)
+ */
+ String topics() default "";
+
+ /**
+ * Enables/Disables synchronous sending.
+ * Default : false (asynchronous)
+ */
+ boolean synchronous() default false;
+
+ /**
+ * Sets the data key in which the data is
+ * put.
+ * Default : user.data
+ */
+ String dataKey() default "user.data";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Subscriber.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Subscriber.java
new file mode 100644
index 0000000..2418944
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/event/Subscriber.java
@@ -0,0 +1,83 @@
+/*
+ * 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.handlers.event;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+/**
+ * Event Admin Subscriber handler.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Subscriber {
+
+ /**
+ * Sets the subscriber name.
+ */
+ String name();
+
+ /**
+ * Sets topics on which event are received.
+ * The topics are separated by a ',' such as in
+ * "foo, bar".
+ * Default : no topics (configured in the instance configuration)
+ */
+ String topics() default "";
+
+ /**
+ * Sets the data key in which the data is
+ * stored.
+ * Default : no key
+ * @deprecated replaced by dataKey
+ */
+ String data_key() default "";
+
+ /**
+ * Sets the data type (type of the received data).
+ * Default : no type.
+ * @deprecated replaced by dataType
+ */
+ String data_type() default "";
+
+ /**
+ * Sets the data key in which the data is
+ * stored.
+ * Default : no key
+ */
+ String dataKey() default "";
+
+ /**
+ * Sets the data type (type of the received data).
+ * Default : no type.
+ */
+ String dataType() default "";
+
+
+ /**
+ * Sets the event filter. Only event matching with the
+ * specified LDAP filter are received.
+ * default : no filter;
+ */
+ String filter() default "";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Config.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Config.java
new file mode 100644
index 0000000..9a0d5e9
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Config.java
@@ -0,0 +1,62 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Handler annotation.
+ * Allows exposing the instances as a JMX MBean.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @deprecated replaced by {@link JMXBean}
+ */
+@Target(ElementType.TYPE)
+public @interface Config {
+
+ /**
+ * Enables or Disables MOSGi usage.
+ * If MOSGi is used, MBeans are exposed with the MOSGi mechanism.
+ * Otherwise the MBean Platform Server is used.
+ * Default : false
+ */
+ boolean usesMOSGi() default false;
+
+ /**
+ * Sets the MBean object name.
+ * Default : 'package-name:factory-name:instance-name'.
+ */
+ String objectname() default "";
+
+ /**
+ * Sets the MBean domain.
+ * Default : 'package-name'
+ */
+ String domain() default "";
+
+ /**
+ * Sets the MBean name.
+ * Default : 'instance-name'
+ */
+ String name() default "";
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXBean.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXBean.java
new file mode 100644
index 0000000..b07abfb
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXBean.java
@@ -0,0 +1,61 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Handler annotation.
+ * Allows exposing the instances as a JMX MBean.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface JMXBean {
+
+ /**
+ * Enables or Disables MOSGi usage.
+ * If MOSGi is used, MBeans are exposed with the MOSGi mechanism.
+ * Otherwise the MBean Platform Server is used.
+ * Default : false
+ */
+ boolean usesMOSGi() default false;
+
+ /**
+ * Sets the MBean object name.
+ * Default : 'package-name:factory-name:instance-name'.
+ */
+ String objectname() default "";
+
+ /**
+ * Sets the MBean domain.
+ * Default : 'package-name'
+ */
+ String domain() default "";
+
+ /**
+ * Sets the MBean name.
+ * Default : 'instance-name'
+ */
+ String name() default "";
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXMethod.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXMethod.java
new file mode 100644
index 0000000..3f957fe
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXMethod.java
@@ -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.
+ */
+package org.apache.felix.ipojo.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Method annotation.
+ * Allows exposing methods in the MBean.
+ * This annotation must be used only if the {@link Config} annotation
+ * is used.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface JMXMethod {
+
+ /**
+ * Gets the method description.
+ * Default : no description
+ */
+ String description() default "";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXProperty.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXProperty.java
new file mode 100644
index 0000000..069878d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/JMXProperty.java
@@ -0,0 +1,55 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Property annotation.
+ * Allows exposing properties in the MBean.
+ * This annotation must be used only if the {@link Config} annotation
+ * is used.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+public @interface JMXProperty {
+
+ /**
+ * Sets the property name.
+ */
+ String name();
+
+ /**
+ * Sets the access permission.
+ * Possible values are 'r' (default) or 'w'.
+ * 'w' implies read and write access.
+ */
+ String rights() default "r";
+
+ /**
+ * Enables notification on the current property.
+ * Notifications are disable by default.
+ */
+ boolean notification() default false;
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Method.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Method.java
new file mode 100644
index 0000000..4fb0cd1
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Method.java
@@ -0,0 +1,43 @@
+/*
+ * 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.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Method annotation.
+ * Allows exposing methods in the MBean.
+ * This annotation must be used only if the {@link Config} annotation
+ * is used.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @deprecated replaced by {@link JMXMethod}
+ */
+@Target(ElementType.METHOD)
+public @interface Method {
+
+ /**
+ * Gets the method description.
+ * Default : no description
+ */
+ String description() default "";
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Property.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Property.java
new file mode 100644
index 0000000..6de9e83
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/handlers/jmx/Property.java
@@ -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.felix.ipojo.handlers.jmx;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * JMX Property annotation.
+ * Allows exposing properties in the MBean.
+ * This annotation must be used only if the {@link Config} annotation
+ * is used.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @deprecated replaced by {@link JMXProperty}
+ */
+@Target(ElementType.FIELD)
+public @interface Property {
+
+ /**
+ * Sets the property name.
+ */
+ String name();
+
+ /**
+ * Sets the access permission.
+ * Possible values are 'r' (default) or 'w'.
+ * 'w' implies read and write access.
+ */
+ String rights() default "r";
+
+ /**
+ * Enables notification on the current property.
+ * Notifications are disable by default.
+ */
+ boolean notification() default false;
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transaction.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transaction.java
new file mode 100644
index 0000000..9860323
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transaction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.transaction;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Transaction Handler annotation.
+ * Allows the declaration of transactionnal methods
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Transaction {
+
+ /**
+ * Sets the Transaction field. The specified field must be of the type
+ * Transaction.
+ */
+ String field() default "";
+
+ /**
+ * Sets the method called when a transaction is committed.
+ */
+ String oncommit() default "";
+
+ /**
+ * Sets the method called when a transaction is rolled back.
+ */
+ String onrollback() default "";
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transactional.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transactional.java
new file mode 100644
index 0000000..f89133d
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/transaction/Transactional.java
@@ -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.felix.ipojo.transaction;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Transactionnal Method annotation.
+ * Allows the declaration of transactionnal method.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface Transactional {
+
+ /**
+ * Sets the transaction timeout.
+ */
+ long timeout() default 0;;
+
+ /**
+ * Sets the transaction propagation policy.
+ * Supported values are : requires mandatory, notsupported, never, requiresnew.
+ */
+ String propagation() default "requires";
+
+ /**
+ * Sets the exceptions that do not rollback the current transaction.
+ */
+ String[] norollbackfor() default { };
+
+ /**
+ * Sets if the transaction rollback throws an exception.
+ */
+ boolean exceptiononrollback() default false;
+
+
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Wbp.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Wbp.java
new file mode 100644
index 0000000..4c66f5e
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Wbp.java
@@ -0,0 +1,54 @@
+/*
+ * 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.whiteboard;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Whiteboard pattern Handler annotation.
+ * Allows configuring a whiteboard pattern.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Wbp {
+
+ /**
+ * Sets the whiteboard pattern filter.
+ */
+ String filter();
+
+ /**
+ * Sets the on service arrival callback.
+ */
+ String onArrival();
+
+ /**
+ * Sets the on service departure callback.
+ */
+ String onDeparture();
+
+ /**
+ * Sets the on service modification callback.
+ * Default : no callback.
+ */
+ String onModification() default "";
+}
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Whiteboards.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Whiteboards.java
new file mode 100644
index 0000000..995bd1c
--- /dev/null
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/whiteboard/Whiteboards.java
@@ -0,0 +1,38 @@
+/*
+ * 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.whiteboard;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Whiteboard pattern Handler annotation.
+ * Allows configuring several whiteboard patterns.
+ * Be aware that despite is it provided in the annotations jar,
+ * it refers to an external handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
+public @interface Whiteboards {
+
+ /**
+ * Whiteboards list.
+ */
+ Wbp[] whiteboards() default {};
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/changelog.txt b/ipojo/manipulator/bnd-ipojo-plugin/changelog.txt
new file mode 100644
index 0000000..aed77ee
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/changelog.txt
@@ -0,0 +1,152 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3461] - Re-manipulation with annotated component produces corrupted MANIFEST
+ * [FELIX-3466] - Pojoization.directoryManipulation() does not take MANIFEST file location into account.
+ * [FELIX-3508] - IPojo Manipulator left out 'array of enums' in generated metadata
+ * [FELIX-3539] - iPOJO Manipulator failed on classes containing expanded frames
+ * [FELIX-3573] - IPojo bytecode manipulation generates a duplicate local variable
+ * [FELIX-3574] - IPojo bytecode manipulation looses method argument names
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+
+Changes from the 1.8.2 to 1.8.4
+-------------------------------
+
+** Bug
+ * [FELIX-3297] - iPOJO Manipulator throws ClassNotFoundException
+ * [FELIX-3359] - Turn around to avoid to use the split verifier on Java 7
+ * [FELIX-3389] - Bnd iPOJO Plugin ignores annotated components
+ * [FELIX-3391] - Unexpected warning when using bnd-ipojo-plugin
+
+Changes in the 1.8.2
+--------------------
+
+** Bug
+ * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files
+ * [FELIX-3012] - "Duplicate name&signature" problem
+ * [FELIX-3098] - iPOJO new manipulator crashes when using a custom reporter
+ * [FELIX-3145] - VerifyError on Java 7
+ * [FELIX-3249] - iPOJO Bnd Plugin do not write all the metadatas in the manifest
+
+** Improvement
+ * [FELIX-3017] - The manipulator should return the original class if it's already manipulated
+ * [FELIX-3078] - Introduce resource abstraction in the iPOJO manipulator
+ * [FELIX-3079] - Adapt the Ant task and the maven plugin to use the new manipulator capabilities
+ * [FELIX-3080] - Implement a BND plugin for iPOJO
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+ * [FELIX-3204] - @Temporal should handle instantiation-time properties
+ * [FELIX-3244] - Manipulator : DefaultManifestBuilder should be more extensible
\ No newline at end of file
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/pom.xml b/ipojo/manipulator/bnd-ipojo-plugin/pom.xml
new file mode 100644
index 0000000..1ae769a
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/pom.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Bnd Plugin</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bndlib</artifactId>
+ <version>2.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.8.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.MF</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..0c8ef39
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed by Peter Kriens
+(http://www.aqute.biz/Code/Bnd)
+Copyright 2006-2011 aQute, All rights reserved
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1 @@
+
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java
new file mode 100644
index 0000000..f555b21
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java
@@ -0,0 +1,243 @@
+/*
+ * 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.bnd;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.util.Constants;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+
+import aQute.bnd.header.Attrs;
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Clazz;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
+import aQute.service.reporter.Reporter;
+
+public class BndJarResourceStore implements ResourceStore {
+
+ private Analyzer m_analyzer;
+ private Reporter m_reporter;
+
+ private MetadataRenderer m_renderer = new MetadataRenderer();
+
+ private List<Element> m_metadata;
+ private boolean m_includeEmbedComponents;
+
+ public BndJarResourceStore(Analyzer analyzer, Reporter reporter) {
+ m_metadata = new ArrayList<Element>();
+ m_analyzer = analyzer;
+ m_reporter = reporter;
+ }
+
+ public byte[] read(String path) throws IOException {
+
+ // Find the resource either in the global jar or in one of the embed dependencies
+ Resource resource = m_analyzer.getJar().getResource(path);
+ if (resource == null) {
+ Jar embed = findJar(path);
+ if (embed == null) {
+ throw new IOException(format("Cannot find resource %s in jar and classpath", path));
+ }
+ resource = embed.getResource(path);
+ }
+ InputStream is = null;
+ try {
+ is = resource.openInputStream();
+ } catch (Exception e) {
+ throw new IOException("Cannot read " + path);
+ }
+ return Streams.readBytes(is);
+ }
+
+ public void accept(ResourceVisitor visitor) {
+
+ try {
+ // Collect all annotated classes
+ Collection<Clazz> classes = m_analyzer.getClasses("",
+ Clazz.QUERY.CLASSANNOTATIONS.name());
+
+ classes = filter(classes);
+
+ // Iterates over discovered resources
+ for (Clazz clazz : classes) {
+ visitor.visit(clazz.getAbsolutePath());
+ }
+ } catch (Exception e) {
+ m_reporter.error("Cannot find iPOJO annotated types: " + e.getMessage());
+ }
+ }
+
+ private Collection<Clazz> filter(Collection<Clazz> classes) throws Exception {
+ Set<Clazz> manipulable = new HashSet<Clazz>();
+ for (Clazz clazz : classes) {
+
+ // If it is in the main jar, simply use it
+ if (m_analyzer.getJar().getResource(clazz.getAbsolutePath()) != null) {
+ manipulable.add(clazz);
+ continue;
+ }
+
+ if (m_includeEmbedComponents) {
+ // Otherwise ...
+ // Try to see if it is in an embed dependencies
+ Jar jar = findJar(clazz.getAbsolutePath());
+ if (jar == null) {
+ m_reporter.error("Resource for class %s not found in classpath", clazz.getFQN());
+ continue;
+ }
+
+ // Is it a Bundle ?
+ if (jar.getBsn() != null) {
+ // OSGi Bundle case
+
+ // Check if the bundle was manipulated before
+ Attributes attr = jar.getManifest().getMainAttributes();
+ if (Manifests.getComponents(attr) != null) {
+ // Bundle has been previously manipulated
+ // TODO We should ignore the resource since it was already manipulated
+ // TODO But we should also merge its IPOJO-Components header
+ } else {
+ // Bundle was not manipulated
+ manipulable.add(clazz);
+ }
+
+ } else {
+ // Simple Jar file with iPOJO annotations
+ m_reporter.warning("Class %s found in a non-Bundle archive %s", clazz.getFQN(), jar.getName());
+ continue;
+ }
+ } else {
+ m_reporter.warning("Embed components are excluded, Component %s will not be manipulated", clazz.getFQN());
+ }
+ }
+ return manipulable;
+ }
+
+ private Jar findJar(String path) {
+ for (Jar jar : m_analyzer.getClasspath()) {
+ if (jar.getResource(path) != null) {
+ return jar;
+ }
+ }
+ return null;
+ }
+
+ public void open() throws IOException {
+ // nothing to do
+ }
+
+ public void writeMetadata(Element metadata) {
+ m_metadata.add(metadata);
+
+ // Find referred packages and add them into Bnd
+ for (String referred : Metadatas.findReferredPackages(metadata)) {
+ if (!m_analyzer.getReferred().containsFQN(referred)) {
+ // The given package is not referred ATM
+ m_analyzer.getReferred().put(m_analyzer.getPackageRef(referred),
+ new Attrs());
+ }
+ }
+
+ // IPOJO-Components will be written during the close method.
+ }
+
+ public void write(String resourcePath, byte[] resource) throws IOException {
+ Jar jar = m_analyzer.getJar();
+ jar.putResource(resourcePath, new ByteArrayResource(resource));
+ }
+
+ public void close() throws IOException {
+
+ // Write the iPOJO header (including manipulation metadata)
+ StringBuilder builder = new StringBuilder();
+
+ if (m_includeEmbedComponents) {
+ // Incorporate metadata of embed dependencies (if any)
+ for (Jar jar : m_analyzer.getClasspath()) {
+ try {
+ Manifest manifest = jar.getManifest();
+ Attributes main = manifest.getMainAttributes();
+ String components = Manifests.getComponents(main);
+ if (components != null) {
+ m_reporter.trace("Merging components from %s", jar.getName());
+ builder.append(components);
+ }
+ } catch (Exception e) {
+ m_reporter.warning("Cannot open MANIFEST of %s", jar.getName());
+ }
+ }
+ }
+
+ for (Element metadata : m_metadata) {
+ builder.append(m_renderer.render(metadata));
+ }
+
+ if (builder.length() != 0) {
+ m_analyzer.setProperty("IPOJO-Components", builder.toString());
+ }
+
+ // Add some mandatory imported packages
+ Attrs version = new Attrs();
+ version.put("version:Version", Constants.getPackageImportClause());
+
+ if (!m_analyzer.getReferred().containsFQN("org.apache.felix.ipojo")) {
+ m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.apache.felix.ipojo"),
+ version);
+ }
+ if (!m_analyzer.getReferred().containsFQN("org.apache.felix.ipojo.architecture")) {
+ m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.apache.felix.ipojo.architecture"),
+ version);
+ }
+ if (!m_analyzer.getReferred().containsFQN("org.osgi.service.cm")) {
+ Attrs cm = new Attrs();
+ cm.put("version:Version", "1.2");
+ m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.osgi.service.cm"),
+ cm);
+ }
+ if (!m_analyzer.getReferred().containsFQN("org.osgi.service.log")) {
+ Attrs log = new Attrs();
+ log.put("version:Version", "1.3");
+ m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.osgi.service.log"),
+ log);
+ }
+
+
+ }
+
+ public void setIncludeEmbedComponents(boolean excludeEmbedComponents) {
+ m_includeEmbedComponents = excludeEmbedComponents;
+ }
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java
new file mode 100644
index 0000000..085d63a
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.bnd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+
+import aQute.service.reporter.Reporter;
+
+/**
+ * A {@code BndReporter} knows how to wrap a Bnd Reporter into an iPOJO Reporter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BndReporter extends EmptyReporter {
+
+ /**
+ * Bnd reporter.
+ */
+ private Reporter m_reporter;
+
+ /**
+ * Errors which occur during the manipulation.
+ */
+ private List<String> m_errors = new ArrayList<String>();
+
+ /**
+ * Warnings which occur during the manipulation.
+ */
+ private List<String> m_warnings = new ArrayList<String>();
+
+ public BndReporter(Reporter reporter) {
+ m_reporter = reporter;
+ }
+
+ public List<String> getErrors() {
+ return m_errors;
+ }
+
+ public List<String> getWarnings() {
+ return m_warnings;
+ }
+
+ @Override
+ public void trace(String message, Object... args) {
+ m_reporter.trace(message, args);
+ }
+
+ @Override
+ public void info(String message, Object... args) {
+ m_reporter.trace(message, args);
+ }
+
+ @Override
+ public void warn(String message, Object... args) {
+ m_reporter.warning(message, args);
+ m_warnings.add(String.format(message, args));
+ }
+
+ @Override
+ public void error(String message, Object... args) {
+ m_reporter.error(message, args);
+ m_errors.add(String.format(message, args));
+ }
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java
new file mode 100644
index 0000000..e2ee7fc
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java
@@ -0,0 +1,43 @@
+/*
+ * 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.bnd;
+
+
+import aQute.bnd.osgi.AbstractResource;
+
+/**
+ * A {@code ByteArrayResource} is ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ByteArrayResource extends AbstractResource {
+
+ private byte[] m_content;
+
+ public ByteArrayResource(byte[] content) {
+ super(System.currentTimeMillis());
+ m_content = content;
+ }
+
+ @Override
+ protected byte[] getBytes() throws Exception {
+ return m_content;
+ }
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/Manifests.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/Manifests.java
new file mode 100644
index 0000000..4d267ca
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/Manifests.java
@@ -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.felix.ipojo.bnd;
+
+import java.util.jar.Attributes;
+
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Jar;
+
+/**
+ * A {@code Manifests} is a utility class for extracting data from Bundle's Manifest.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Manifests {
+ private Manifests() {}
+
+ public static String getComponents(Attributes main) {
+ String value = main.getValue("iPOJO-Components");
+ if (value == null) {
+ value = main.getValue("IPOJO-Components");
+ }
+
+ return value;
+ }
+
+ public static boolean hasEmbedComponents(Analyzer analyzer) throws Exception {
+ for (Jar jar : analyzer.getClasspath()) {
+ // Check if the bundle was manipulated before
+ Attributes attr = jar.getManifest().getMainAttributes();
+ if (getComponents(attr) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java
new file mode 100644
index 0000000..09dc02a
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java
@@ -0,0 +1,191 @@
+/*
+ * 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.bnd;
+
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
+import aQute.bnd.service.AnalyzerPlugin;
+import aQute.bnd.service.Plugin;
+import aQute.service.reporter.Reporter;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.AnnotationMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.CacheableMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.CompositeMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.FileMetadataProvider;
+import org.apache.felix.ipojo.manipulator.util.Classpath;
+import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor;
+import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * A {@code BndIpojoPlugin} is ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PojoizationPlugin implements Plugin, AnalyzerPlugin {
+
+ private static final String PROPERTY_METADATA = "metadata";
+ private static final String PROPERTY_USE_LOCAL_SCHEMAS = "use-local-schemas";
+ private static final String PROPERTY_INCLUDE_EMBED_BUNDLES = "include-embed-bundles";
+
+ private static final String DEFAULT_METADATA = "META-INF/metadata.xml";
+ private static final boolean DEFAULT_USE_LOCAL_SCHEMAS = false;
+ private static final boolean DEFAULT_INCLUDE_EMBED_BUNDLES = false;
+
+ private String m_metadata = DEFAULT_METADATA;
+ private boolean m_useLocalSchemas = DEFAULT_USE_LOCAL_SCHEMAS;
+ private boolean m_includeEmbedBundles = DEFAULT_INCLUDE_EMBED_BUNDLES;
+
+ private Reporter m_reporter;
+
+ public void setProperties(Map<String, String> configuration) {
+
+ // Use metadata file if any
+ if (configuration.containsKey(PROPERTY_METADATA)) {
+ m_metadata = configuration.get(PROPERTY_METADATA);
+ }
+
+ // Use local schemas ?
+ if (configuration.containsKey(PROPERTY_USE_LOCAL_SCHEMAS)) {
+ m_useLocalSchemas = true;
+ }
+
+ // Process embed bundles ?
+ if (configuration.containsKey(PROPERTY_INCLUDE_EMBED_BUNDLES)) {
+ m_includeEmbedBundles = true;
+ }
+ }
+
+ public void setReporter(Reporter reporter) {
+ m_reporter = reporter;
+ }
+
+ public boolean analyzeJar(Analyzer analyzer) throws Exception {
+
+ long start = System.currentTimeMillis();
+
+ // Wraps the Bnd Reporter
+ BndReporter reporter = new BndReporter(this.m_reporter);
+
+ // Build ResourceStore
+ BndJarResourceStore store = new BndJarResourceStore(analyzer, this.m_reporter);
+ store.setIncludeEmbedComponents(m_includeEmbedBundles);
+
+ CompositeMetadataProvider provider = buildMetadataProvider(analyzer, reporter, store);
+
+ // Quick exit
+ CacheableMetadataProvider cache = new CacheableMetadataProvider(provider);
+ if (cache.getMetadatas().isEmpty() && !hasEmbedComponents(analyzer)) {
+ return false;
+ }
+
+ // Compute the classpath to build the classloader.
+ List<Jar> jars = analyzer.getClasspath();
+ Jar jar = analyzer.getJar();
+
+ Set<String> paths = new LinkedHashSet<String>();
+ if (jar != null && jar.getSource() != null) {
+ paths.add(jar.getSource().getAbsolutePath());
+ }
+ for (Jar j : jars) {
+ if (j.getSource() != null) {
+ paths.add(j.getSource().getAbsolutePath());
+ }
+ }
+ Classpath cp = new Classpath(paths);
+ manipulateComponents(reporter, store, cache, cp.createClassLoader());
+
+ int nbComponents = findElements(cache.getMetadatas(), "component").size();
+ int nbHandlers = findElements(cache.getMetadatas(), "handler").size();
+ this.m_reporter.trace("iPOJO manipulation performed performed in %s ms (%d components, %d handlers).",
+ (System.currentTimeMillis() - start),
+ nbComponents,
+ nbHandlers);
+ // Return true if a new run should be performed after the analyze
+ return false;
+ }
+
+ protected void manipulateComponents(BndReporter reporter, BndJarResourceStore store,
+ CacheableMetadataProvider cache, ClassLoader classLoader) {
+ Pojoization pojoization = new Pojoization(reporter);
+ pojoization.disableAnnotationProcessing();
+ if (m_useLocalSchemas) {
+ pojoization.setUseLocalXSD();
+ }
+
+ pojoization.pojoization(store, cache, createVisitor(store, reporter), classLoader);
+ }
+
+ protected CompositeMetadataProvider buildMetadataProvider(Analyzer analyzer, BndReporter reporter, BndJarResourceStore store) {
+ // Build MetadataProvider
+ CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+
+ File file = new File(m_metadata);
+ if (file.exists()) {
+ // Absolute file system resource
+ FileMetadataProvider fmp = new FileMetadataProvider(file, reporter);
+ fmp.setValidateUsingLocalSchemas(m_useLocalSchemas);
+ provider.addMetadataProvider(fmp);
+ } else {
+ // In archive resource
+ Resource resource = analyzer.getJar().getResource(m_metadata);
+ if (resource != null) {
+ ResourceMetadataProvider rmp = new ResourceMetadataProvider(resource, reporter);
+ rmp.setValidateUsingLocalSchemas(m_useLocalSchemas);
+ provider.addMetadataProvider(rmp);
+ }
+ }
+ provider.addMetadataProvider(new AnnotationMetadataProvider(store, reporter));
+ return provider;
+ }
+
+ private boolean hasEmbedComponents(Analyzer analyzer) throws Exception {
+ // We want to process components from embed jars ?
+ return m_includeEmbedBundles && Manifests.hasEmbedComponents(analyzer);
+
+ }
+
+ private List<Element> findElements(List<Element> metadatas, String name) {
+ List<Element> found = new ArrayList<Element>();
+ for (Element element : metadatas) {
+ if (name.equalsIgnoreCase(element.getName())) {
+ found.add(element);
+ }
+ }
+ return found;
+ }
+
+ protected ManipulationVisitor createVisitor(ResourceStore store, BndReporter reporter) {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(reporter);
+ writer.setResourceStore(store);
+
+ CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer);
+ checkFieldConsistencyVisitor.setReporter(reporter);
+ return checkFieldConsistencyVisitor;
+ }
+
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java
new file mode 100644
index 0000000..e696b60
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java
@@ -0,0 +1,75 @@
+/*
+ * 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.bnd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.StreamMetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+import aQute.bnd.osgi.Resource;
+
+/**
+ * A {@code ResourceMetadataProvider} is ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResourceMetadataProvider implements MetadataProvider {
+
+ private Resource m_resource;
+
+ private List<Element> m_cached;
+
+ private boolean m_validateUsingLocalSchemas = false;
+
+ private Reporter m_reporter;
+
+ public ResourceMetadataProvider(Resource resource, Reporter reporter) {
+ m_resource = resource;
+ m_reporter = reporter;
+ }
+
+ public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+ this.m_validateUsingLocalSchemas = validateUsingLocalSchemas;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+ if (m_cached == null) {
+ m_cached = new ArrayList<Element>();
+ InputStream stream = null;
+ try {
+ stream = m_resource.openInputStream();
+ } catch (Exception e) {
+ m_reporter.error("%s", e.getMessage());
+ throw new IOException("Cannot read metadata", e);
+ }
+ StreamMetadataProvider provider = new StreamMetadataProvider(stream, m_reporter);
+ provider.setValidateUsingLocalSchemas(m_validateUsingLocalSchemas);
+ m_cached.addAll(provider.getMetadatas());
+ }
+
+ return m_cached;
+ }
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/BndJarResourceStoreTestCase.java b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/BndJarResourceStoreTestCase.java
new file mode 100644
index 0000000..3a425fd
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/BndJarResourceStoreTestCase.java
@@ -0,0 +1,170 @@
+/*
+ * 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.bnd;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Clazz;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
+import aQute.bnd.osgi.URLResource;
+import aQute.service.reporter.Reporter;
+import junit.framework.TestCase;
+
+/**
+ * Checks the Resource Store from the BND plugin.
+ */
+public class BndJarResourceStoreTestCase extends TestCase {
+ @Mock
+ private Reporter reporter;
+
+ @Spy
+ private Analyzer analyzer = new Analyzer();
+
+ @Spy
+ private Jar dot = new Jar("root.jar");
+
+ @Spy
+ private Jar embed = new Jar("embed.jar");
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testAnalysisWithOnlyEmbedComponents() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+ props.put("include-embed-bundles", "true");
+
+ Resource resource = new URLResource(getClass().getResource("/EMBED-MANIFEST.MF"));
+ doReturn(dot).when(analyzer).getJar();
+ doReturn(resource).when(embed).getResource(eq("META-INF/MANIFEST.MF"));
+ analyzer.setClasspath(new Jar[] {embed});
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertContains("instance { $component=\"org.apache.felix.ipojo.IPOJOURLHandler\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ }
+
+ public void testAnalysisWithExcludedEmbedComponents() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+
+ Resource resource = new URLResource(getClass().getResource("/EMBED-MANIFEST.MF"));
+ doReturn(dot).when(analyzer).getJar();
+ doReturn(resource).when(embed).getResource(eq("META-INF/MANIFEST.MF"));
+ analyzer.setClasspath(new Jar[] {embed});
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertNull(analyzer.getProperty("IPOJO-Components"));
+ }
+
+
+ public void testAnalysisWithBothLocalAndEmbedComponents() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+ props.put("include-embed-bundles", "true");
+
+ Resource resource = new URLResource(getClass().getResource("/EMBED-MANIFEST.MF"));
+ Resource resource2 = new URLResource(getClass().getResource("/metadata-components-only.xml"));
+ doReturn(dot).when(analyzer).getJar();
+ doReturn(resource).when(embed).getResource(eq("META-INF/MANIFEST.MF"));
+ doReturn(resource2).when(dot).getResource(eq("META-INF/metadata.xml"));
+ analyzer.setClasspath(new Jar[]{embed});
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertContains("instance { $component=\"org.apache.felix.ipojo.IPOJOURLHandler\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ assertContains("component { $class=\"com.acme.Thermometer\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ }
+
+
+ public void testAnalysisWithLocallyDefinedComponentAndEmbedResource() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+ props.put("include-embed-bundles", "true");
+ String path = EmptyComponent.class.getName().replace('.', '/').concat(".class");
+
+ Resource resource2 = new URLResource(getClass().getResource("/metadata-test-component.xml"));
+ doReturn(dot).when(analyzer).getJar();
+ doReturn(resource2).when(dot).getResource(eq("META-INF/metadata.xml"));
+
+ Collection<Clazz> classes = new ArrayList<Clazz>();
+ Resource typeResource = new URLResource(getClass().getResource("EmptyComponent.class"));
+ Clazz clazz = new Clazz(analyzer, path, typeResource);
+ clazz.parseClassFile();
+ classes.add(clazz);
+ doReturn(classes).when(analyzer).getClasses(Matchers.<String[]>anyVararg());
+
+ Resource resource = new URLResource(getClass().getResource("/EMBED-MANIFEST-EMPTY.MF"));
+ doReturn(resource).when(embed).getResource(eq("META-INF/MANIFEST.MF"));
+ doReturn(typeResource).when(embed).getResource(path);
+ doReturn("aaa").when(embed).getBsn();
+
+ analyzer.setClasspath(new Jar[] {embed});
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertContains("component { $classname=\"org.apache.felix.ipojo.bnd.EmptyComponent\" manipulation { $classname=\"org.apache.felix.ipojo.bnd.EmptyComponent\" method { $name=\"$init\" }}}",
+ analyzer.getProperty("IPOJO-Components"));
+ verify(dot).putResource(eq(path), any(Resource.class));
+ }
+
+ private void assertContains(String expected, String actual) {
+ System.out.println("Actual: " + actual);
+ assertTrue(actual.contains(expected));
+ }
+
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/EmptyComponent.java b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/EmptyComponent.java
new file mode 100644
index 0000000..6ea32e5
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/EmptyComponent.java
@@ -0,0 +1,31 @@
+/*
+ * 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.bnd;
+
+/**
+* Created with IntelliJ IDEA.
+* User: guillaume
+* Date: 07/01/13
+* Time: 11:31
+* To change this template use File | Settings | File Templates.
+*/
+public class EmptyComponent {
+
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/PojoizationPluginTestCase.java b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/PojoizationPluginTestCase.java
new file mode 100644
index 0000000..97837ad
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/java/org/apache/felix/ipojo/bnd/PojoizationPluginTestCase.java
@@ -0,0 +1,110 @@
+/*
+ * 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.bnd;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
+import aQute.bnd.osgi.URLResource;
+import aQute.service.reporter.Reporter;
+import junit.framework.TestCase;
+
+public class PojoizationPluginTestCase extends TestCase {
+
+ @Mock
+ private Reporter reporter;
+
+ @Spy
+ private Analyzer analyzer = new Analyzer();
+
+ @Spy
+ private Jar jar = new Jar("mock.jar");
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testAnalysisWithComponentOnlyMetadataXml() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+
+ Resource resource = new URLResource(getClass().getResource("/metadata-components-only.xml"));
+ doReturn(jar).when(analyzer).getJar();
+ doReturn(resource).when(jar).getResource(eq("META-INF/metadata.xml"));
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertEquals("component { $class=\"com.acme.Thermometer\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ }
+
+ public void testAnalysisWithInstanceOnlyMetadataXml() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+
+ Resource resource = new URLResource(getClass().getResource("/metadata-instances-only.xml"));
+ doReturn(jar).when(analyzer).getJar();
+ doReturn(resource).when(jar).getResource(eq("META-INF/metadata.xml"));
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertEquals("instance { $component=\"com.acme.Thermometer\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ }
+
+ public void testAnalysisWithComponentsAndInstancesMetadataXml() throws Exception {
+ PojoizationPlugin plugin = new PojoizationPlugin();
+
+ Map<String, String> props = new HashMap<String, String>();
+
+ Resource resource = new URLResource(getClass().getResource("/metadata-components-and-instances.xml"));
+ doReturn(jar).when(analyzer).getJar();
+ doReturn(resource).when(jar).getResource(eq("META-INF/metadata.xml"));
+
+ plugin.setReporter(reporter);
+ plugin.setProperties(props);
+
+ plugin.analyzeJar(analyzer);
+
+ assertEquals("component { $class=\"com.acme.Thermometer\" }" +
+ "instance { $component=\"com.acme.Thermometer\" }" +
+ "instance { $component=\"com.acme.Thermometer\" }",
+ analyzer.getProperty("IPOJO-Components"));
+ }
+}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST-EMPTY.MF b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST-EMPTY.MF
new file mode 100644
index 0000000..bc04d39
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST-EMPTY.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Bundle-Name: Embed
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.apache.felix.ipojo.test
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST.MF b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST.MF
new file mode 100644
index 0000000..b19fc3e
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/EMBED-MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-Name: Embed
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.apache.felix.ipojo.test
+IPOJO-Components: instance { $component="org.apache.felix.ipojo.IPOJOU
+ RLHandler" }component { $immediate="true" $classname="org.apache.feli
+ x.ipojo.IPOJOURLHandler" $public="false" callback { $transition="inva
+ lidate" $method="stop" }provides { property { $mandatory="false" $nam
+ e="url.handler.protocol" $value="ipojo" $type="java.lang.String" }}ma
+ nipulation { $super="org.osgi.service.url.AbstractURLStreamHandlerSer
+ vice" field { $name="m_context" $type="org.osgi.framework.BundleConte
+ xt" }field { $name="m_temp" $type="java.io.File" }method { $arguments
+ ="{org.osgi.framework.BundleContext}" $name="$init" }method { $name="
+ stop" }method { $arguments="{java.net.URL}" $name="openConnection" $r
+ eturn="java.net.URLConnection" }method { $arguments="{java.net.URL,ja
+ va.io.File}" $name="save" }method { $arguments="{java.io.InputStream,
+ java.io.File}" $name="save" }method { $arguments="{java.util.jar.JarF
+ ile}" $name="findMetadata" $return="java.io.File" }interface { $name=
+ "org.osgi.service.url.URLStreamHandlerService" }}}
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-and-instances.xml b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-and-instances.xml
new file mode 100644
index 0000000..3b1473e
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-and-instances.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component class="com.acme.Thermometer" />
+ <instance component="com.acme.Thermometer" />
+ <instance component="com.acme.Thermometer" />
+</ipojo>
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-only.xml b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-only.xml
new file mode 100644
index 0000000..466d6fb
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-components-only.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component class="com.acme.Thermometer"/>
+</ipojo>
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-instances-only.xml b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-instances-only.xml
new file mode 100644
index 0000000..870c6ed
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-instances-only.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <instance component="com.acme.Thermometer"/>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-test-component.xml b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-test-component.xml
new file mode 100644
index 0000000..8df4c4c
--- /dev/null
+++ b/ipojo/manipulator/bnd-ipojo-plugin/src/test/resources/metadata-test-component.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component classname="org.apache.felix.ipojo.bnd.EmptyComponent"/>
+</ipojo>
diff --git a/ipojo/manipulator/changelog.txt b/ipojo/manipulator/changelog.txt
new file mode 100644
index 0000000..b8de1f5
--- /dev/null
+++ b/ipojo/manipulator/changelog.txt
@@ -0,0 +1,152 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3461] - Re-manipulation with annotated component produces corrupted MANIFEST
+ * [FELIX-3466] - Pojoization.directoryManipulation() does not take MANIFEST file location into account.
+ * [FELIX-3508] - IPojo Manipulator left out 'array of enums' in generated metadata
+ * [FELIX-3539] - iPOJO Manipulator failed on classes containing expanded frames
+ * [FELIX-3573] - IPojo bytecode manipulation generates a duplicate local variable
+ * [FELIX-3574] - IPojo bytecode manipulation looses method argument names
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+
+
+Changes from the 1.8.2 to 1.8.4
+-------------------------------
+
+** Bug
+ * [FELIX-3297] - iPOJO Manipulator throws ClassNotFoundException
+ * [FELIX-3359] - Turn around to avoid to use the split verifier on Java 7
+
+Changes in the 1.8.2
+--------------------
+
+** Bug
+ * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files
+ * [FELIX-3012] - "Duplicate name&signature" problem
+ * [FELIX-3098] - iPOJO new manipulator crashes when using a custom reporter
+ * [FELIX-3145] - VerifyError on Java 7
+ * [FELIX-3249] - iPOJO Bnd Plugin do not write all the metadatas in the manifest
+
+** Improvement
+ * [FELIX-3017] - The manipulator should return the original class if it's already manipulated
+ * [FELIX-3078] - Introduce resource abstraction in the iPOJO manipulator
+ * [FELIX-3079] - Adapt the Ant task and the maven plugin to use the new manipulator capabilities
+ * [FELIX-3080] - Implement a BND plugin for iPOJO
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+ * [FELIX-3204] - @Temporal should handle instantiation-time properties
+ * [FELIX-3244] - Manipulator : DefaultManifestBuilder should be more extensible
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/changelog.txt b/ipojo/manipulator/ipojo-ant-task/changelog.txt
new file mode 100644
index 0000000..1755347
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/changelog.txt
@@ -0,0 +1,197 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3461] - Re-manipulation with annotated component produces corrupted MANIFEST
+ * [FELIX-3466] - Pojoization.directoryManipulation() does not take MANIFEST file location into account.
+ * [FELIX-3508] - IPojo Manipulator left out 'array of enums' in generated metadata
+ * [FELIX-3539] - iPOJO Manipulator failed on classes containing expanded frames
+ * [FELIX-3573] - IPojo bytecode manipulation generates a duplicate local variable
+ * [FELIX-3574] - IPojo bytecode manipulation looses method argument names
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+
+Changes from the 1.8.2 to 1.8.4
+-------------------------------
+
+** Bug
+ * [FELIX-3297] - iPOJO Manipulator throws ClassNotFoundException
+ * [FELIX-3359] - Turn around to avoid to use the split verifier on Java 7
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+
+** Bug
+ * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files
+ * [FELIX-3012] - "Duplicate name&signature" problem
+ * [FELIX-3098] - iPOJO new manipulator crashes when using a custom reporter
+ * [FELIX-3145] - VerifyError on Java 7
+ * [FELIX-3249] - iPOJO Bnd Plugin do not write all the metadatas in the manifest
+
+** Improvement
+ * [FELIX-3017] - The manipulator should return the original class if it's already manipulated
+ * [FELIX-3078] - Introduce resource abstraction in the iPOJO manipulator
+ * [FELIX-3079] - Adapt the Ant task and the maven plugin to use the new manipulator capabilities
+ * [FELIX-3080] - Implement a BND plugin for iPOJO
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+ * [FELIX-3204] - @Temporal should handle instantiation-time properties
+ * [FELIX-3244] - Manipulator : DefaultManifestBuilder should be more extensible
+
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Improvement
+ * [FELIX-2755] - Allow the manipulator and the different front end to use several metadata files
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1411] - Issue on windows to find components inside bundle
+
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from the 1.4.0 to 1.4.2
+-------------------------------
+** Bug
+ * [FELIX-1411] - Issue on windows to find components inside bundle
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1302] - Manipulator never ignore annotations
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-813] - Resolve XML-Schemas locally rather than from Internet
+
+Changes from 0.8.1 to 1.0.0
+---------------------------
+** Bug
+ * Update contained Xerces packages to support XML-Schemas
+
+** Improvement
+ * Embed the latest manipulator
+
+Version 0.8.1
+-------------
+ * Initial release
diff --git a/ipojo/manipulator/ipojo-ant-task/pom.xml b/ipojo/manipulator/ipojo-ant-task/pom.xml
new file mode 100644
index 0000000..06813a4
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/pom.xml
@@ -0,0 +1,166 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.ant</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Ant Task</name>
+
+ <description>
+ Ant task to package iPOJO-powered bundles.
+ </description>
+
+ <properties>
+ <ipojo.import.packages>[1.12.1,2.0.0)</ipojo.import.packages>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.6.5</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.2</version>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>iPOJO Ant Task</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Ant Task</Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-ant-task.html
+ </Bundle-DocURL>
+ <Private-Package>
+ org.apache.felix.ipojo.metadata,
+ org.apache.felix.ipojo.manipulator*,
+ org.apache.felix.ipojo.xml.parser,
+ org.apache.felix.ipojo.manipulation*,
+ org.apache.felix.ipojo.annotations*,
+ org.objectweb.asm.util;-split-package:=merge-first,
+ org.objectweb.asm;-split-package:=merge-first,
+ org.objectweb.asm.commons;-split-package:=merge-first,
+ org.objectweb.asm.tree*;-split-package:=merge-first,
+ org.apache.xerces.parsers, org.apache.xerces.xni*,
+ org.apache.xerces.impl*, org.apache.xerces.util.*,
+ org.apache.xerces.dom.*, org.apache.xerces.dom3.*,
+ <!-- commons-cli -->
+ org.apache.commons.cli
+ </Private-Package>
+ <Export-Package>org.apache.felix.ipojo.task</Export-Package>
+ <Main-Class>org.apache.felix.ipojo.task.IPojoc</Main-Class>
+ </instructions>
+ <obrRepository>NONE</obrRepository>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
+ </exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..caa7b23
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/LICENSE b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..b42de54
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Ant Task:
+
+The Apache Felix iPOJO Ant Task includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..016e60d
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/AntReporter.java b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/AntReporter.java
new file mode 100644
index 0000000..b99b852
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/AntReporter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.task;
+
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+import org.apache.tools.ant.Project;
+
+/**
+ * An {@code AntReporter} wraps an Ant project (central place for logging in ant
+ * into an iPOJO Reporter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AntReporter extends EmptyReporter {
+
+ /**
+ * Ant Project (used for log).
+ */
+ private Project project;
+
+ public AntReporter(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public void trace(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ project.log(formatted, Project.MSG_DEBUG);
+ }
+
+ @Override
+ public void info(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ project.log(formatted, Project.MSG_INFO);
+ }
+
+ @Override
+ public void warn(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ project.log(formatted, Project.MSG_WARN);
+ getWarnings().add(formatted);
+ }
+
+ @Override
+ public void error(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ project.log(formatted, Project.MSG_ERR);
+ getErrors().add(formatted);
+ }
+
+}
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java
new file mode 100644
index 0000000..ddbb062
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java
@@ -0,0 +1,348 @@
+/*
+ * 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.task;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+import java.io.File;
+
+/**
+ * iPOJO Ant Task. This Ant task manipulates an input bundle.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IPojoTask extends Task {
+
+ /**
+ * Metadata file.
+ */
+ private File m_metadata;
+
+ /**
+ * Input bundle.
+ */
+ private File m_input;
+
+ /**
+ * Output bundle.
+ */
+ private File m_output;
+
+ /**
+ * Input directory.
+ */
+ private File m_directory;
+
+ /**
+ * Input manifest.
+ */
+ private File m_manifest;
+
+ /**
+ * Flag describing if we need to ignore annotation of not.
+ */
+ private boolean m_ignoreAnnotations = false;
+
+
+ /**
+ * Flag describing if we need or not use local XSD files
+ * (i.e. use the {@link org.apache.felix.ipojo.xml.parser.SchemaResolver} or not).
+ * If <code>true</code> the local XSD are not used.
+ */
+ private boolean m_ignoreLocalXSD = false;
+
+ /**
+ * The classpath.
+ */
+ private Path m_classpath;
+
+ /**
+ * Set the metadata file.
+ *
+ * @param meta : the metadata file.
+ */
+ public void setMetadata(File meta) {
+ m_metadata = meta;
+ }
+
+ /**
+ * Set the manifest file.
+ *
+ * @param manifest : the manifest file.
+ */
+ public void setManifest(File manifest) {
+ m_manifest = manifest;
+ }
+
+ /**
+ * Set the input bundle.
+ *
+ * @param in : the input bundle
+ */
+ public void setInput(File in) {
+ m_input = in;
+ }
+
+ /**
+ * Set the input directory.
+ *
+ * @param dir : the input directory
+ */
+ public void setDir(File dir) {
+ m_directory = dir;
+ }
+
+ /**
+ * Set the output bundle.
+ *
+ * @param out : the output bundle
+ */
+ public void setOutput(File out) {
+ m_output = out;
+ }
+
+ /**
+ * Set if we need to ignore annotations or not.
+ *
+ * @param flag : true if we need to ignore annotations.
+ */
+ public void setIgnoreAnnotations(boolean flag) {
+ m_ignoreAnnotations = flag;
+ }
+
+ /**
+ * Set if we need to use embedded XSD files or not.
+ *
+ * @param flag : true if we need to ignore embedded XSD files.
+ */
+ public void setIgnoreEmbeddedSchemas(boolean flag) {
+ m_ignoreLocalXSD = flag;
+ }
+
+ /**
+ * Execute the Ant Task.
+ *
+ * @see org.apache.tools.ant.Task#execute()
+ */
+ public void execute() {
+
+ if (m_input == null && m_directory == null) {
+ throw new BuildException("Neither input bundle nor directory specified");
+ }
+
+ if (m_input != null && !m_input.exists()) {
+ throw new BuildException("The input bundle " + m_input.getAbsolutePath() + " does not exist");
+ }
+
+ if (m_directory != null && !m_directory.exists()) {
+ throw new BuildException("The input directory " + m_directory.getAbsolutePath() + " does not exist");
+ }
+ if (m_directory != null && !m_directory.isDirectory()) {
+ throw new BuildException("The input directory " + m_directory.getAbsolutePath() + " is not a directory");
+ }
+
+
+ if (m_input != null) {
+ log("Input bundle file : " + m_input.getAbsolutePath());
+ } else {
+ log("Input directory : " + m_directory.getAbsolutePath());
+ }
+
+ if (m_manifest != null) {
+ if (m_input != null) {
+ throw new BuildException("The manifest location cannot be used when manipulating an existing bundle");
+ }
+ if (!m_manifest.exists()) {
+ throw new BuildException("The manifest file " + m_manifest.getAbsolutePath() + " does not exist");
+ }
+ }
+
+ // Get metadata file
+ if (m_metadata == null) {
+ m_metadata = new File("./metadata.xml");
+ if (!m_metadata.exists()) {
+ // Verify if annotations are ignored
+ if (m_ignoreAnnotations) {
+ log("No metadata file found & annotations ignored : nothing to do");
+ return;
+ } else {
+ log("No metadata file found - trying to use only annotations");
+ m_metadata = null;
+ }
+ } else {
+ log("Metadata file : " + m_metadata.getAbsolutePath());
+ }
+ } else {
+ // Metadata file is specified, check existence
+ if (!m_metadata.exists()) {
+ throw new BuildException("No metadata file found - the file " + m_metadata.getAbsolutePath() + " does not exist");
+ } else {
+ if (m_metadata.isDirectory()) {
+ log("Metadata directory : " + m_metadata.getAbsolutePath());
+ } else {
+ log("Metadata file : " + m_metadata.getAbsolutePath());
+ }
+ }
+ }
+
+ initializeSaxDriver();
+
+
+ log("Start manipulation");
+
+ if (m_input != null) { // Prepare output file
+ if (m_output == null) {
+ m_output = new File("./_out.jar");
+ }
+ if (m_output.exists()) {
+ boolean r = m_output.delete();
+ if (!r) {
+ throw new BuildException("The file " + m_output.getAbsolutePath() + " cannot be deleted");
+ }
+ }
+ }
+
+ AntReporter reporter = new AntReporter(getProject());
+ Pojoization pojo = new Pojoization(reporter);
+ if (m_ignoreAnnotations) {
+ pojo.disableAnnotationProcessing();
+ }
+ if (!m_ignoreLocalXSD) {
+ pojo.setUseLocalXSD();
+ }
+
+ Path classpath = getClasspath();
+ classpath.addJavaRuntime();
+
+ // Adding the input jar or directory
+ if (m_classpath == null) {
+ m_classpath = createClasspath();
+ }
+ Path element = m_classpath.createPath();
+ if (m_input != null) {
+ element.setLocation(m_input.getAbsoluteFile());
+ } else if (m_directory != null) {
+ element.setLocation(m_directory.getAbsoluteFile());
+ }
+ m_classpath.add(element);
+
+ ClassLoader loader = getProject().createClassLoader(getClasspath());
+ if (m_input != null) {
+ pojo.pojoization(m_input, m_output, m_metadata, loader);
+ } else {
+ pojo.directoryPojoization(m_directory, m_metadata, m_manifest, loader);
+ }
+ for (int i = 0; i < reporter.getWarnings().size(); i++) {
+ log((String) reporter.getWarnings().get(i), Project.MSG_WARN);
+ }
+ if (reporter.getErrors().size() > 0) {
+ throw new BuildException((String) reporter.getErrors().get(0));
+ }
+
+ if (m_input != null) {
+ String out;
+ if (m_output.getName().equals("_out.jar")) {
+ if (m_input.delete()) {
+ if (!m_output.renameTo(m_input)) {
+ log("Cannot rename the output jar to " + m_input.getAbsolutePath(), Project.MSG_WARN);
+ }
+ } else {
+ log("Cannot delete the input file : " + m_input.getAbsolutePath(), Project.MSG_WARN);
+ }
+ out = m_input.getAbsolutePath();
+ } else {
+ out = m_output.getAbsolutePath();
+ }
+
+ log("Bundle manipulation - SUCCESS");
+ log("Output file : " + out);
+ } else {
+ log("Manipulation - SUCCESS");
+ log("Output files : " + m_directory.getAbsolutePath());
+ if (m_manifest != null) {
+ log("Manifest : " + m_manifest.getAbsolutePath());
+ }
+
+ }
+
+ }
+
+ /**
+ * If Ant runs with Java 1.4, we should use the embedded Xerces.
+ * To achieve that, we set the org.xml.sax.driver property.
+ * Otherwise, the JVM sets the org.xml.sax.driver property.
+ */
+ private void initializeSaxDriver() {
+ String version = (String) System.getProperty("java.vm.version");
+ if (version.startsWith("1.4")) {
+ System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
+ }
+ }
+
+ /**
+ * Set the classpath to be used for this packaging.
+ *
+ * @param classpath the classpath used for this packaging
+ */
+ public synchronized void setClasspath(Path classpath) {
+ if (m_classpath == null) {
+ m_classpath = createClasspath();
+ }
+ m_classpath.append(classpath);
+ }
+
+ /**
+ * Creates a nested classpath element.
+ *
+ * @return classpath
+ */
+ public synchronized Path createClasspath() {
+ if (m_classpath == null) {
+ m_classpath = new Path(getProject());
+ }
+ return m_classpath.createPath();
+ }
+
+ /**
+ * Adds to the classpath a reference to
+ * a <path> defined elsewhere.
+ *
+ * @param pathRef the reference to add to the classpath
+ */
+ public void setClasspathRef(Reference pathRef) {
+ createClasspath().setRefid(pathRef);
+ }
+
+ /**
+ * Gets the classpath.
+ *
+ * @return the classpath
+ */
+ public Path getClasspath() {
+ return m_classpath;
+ }
+
+
+}
+
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoc.java b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoc.java
new file mode 100644
index 0000000..8260742
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/java/org/apache/felix/ipojo/task/IPojoc.java
@@ -0,0 +1,247 @@
+/*
+ * 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.task;
+
+import static java.lang.String.format;
+
+import org.apache.commons.cli.*;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.util.Constants;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A command line tools to manipulate iPOJO bundles.
+ * It can be used as follow:
+ * <code>java -jar this-jar.jar --input the-jar-to-manipulate</code><br/>
+ * <code>java -jar this-jar.jar --input the-jar-to-manipulate --output the-output-jar</code><br/>
+ * <code>java -jar this-jar.jar --input the-jar-to-manipulate --metadata the-xml-metadata</code><br/>
+ */
+public class IPojoc {
+
+ /**
+ * Input file to be manipulated.
+ */
+ private File m_input;
+
+ /**
+ * Output file (temporary or not).
+ */
+ private File m_output;
+
+ /**
+ * Metadata file (may be null).
+ */
+ private File m_metadata;
+
+ /**
+ * Manipulator.
+ */
+ private Pojoization m_pojoization;
+
+ /**
+ * The main entry point
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ Options options = buildOptions();
+ CommandLine cmd = null;
+ try {
+ cmd = buildCommandLine(args, options);
+ if (cmd.hasOption('h')) {
+ printHelp(options);
+ } else {
+ IPojoc compiler = new IPojoc();
+ compiler.execute(cmd);
+ }
+ } catch (MissingOptionException e) {
+ for (String opt : (List<String>) e.getMissingOptions()) {
+ System.err.println("The '" + opt + "' option is missing");
+ }
+ printHelp(options);
+ } catch (MissingArgumentException e) {
+ System.err.println("The option '" + e.getOption() + "' requires an argument");
+ printHelp(options);
+ } catch (Exception e) {
+ System.out.printf("Manipulation failed: %s%n", e.getMessage());
+ if ((cmd != null) && cmd.hasOption('X')) {
+ e.printStackTrace(System.out);
+ } else {
+ System.out.printf("Use -X option to print the full stack trace%n");
+ }
+ }
+ }
+
+ private static CommandLine buildCommandLine(final String[] args, final Options options) throws ParseException {
+ CommandLineParser parser = new GnuParser();
+ return parser.parse(options, args);
+ }
+
+ /**
+ * The command line is valid, to processing the command line.
+ * @param cmd the command line
+ * @throws ParseException
+ */
+ private void execute(CommandLine cmd) throws Exception {
+ System.out.printf("iPOJO Manipulation (%s)%n", Constants.getVersion());
+ System.out.println("-----------------------------------------------");
+ readInputOption(cmd);
+ readOutputOption(cmd);
+ readMetadataOption(cmd);
+
+ manipulate();
+ printStatus();
+ }
+
+ private void readMetadataOption(final CommandLine cmd) throws Exception {
+ // Retrieve the metadata file
+ if (cmd.hasOption("m")) {
+ m_metadata = (File) cmd.getParsedOptionValue("m");
+ if (m_metadata != null && !m_metadata.isFile()) {
+ throw new Exception(
+ format("The metadata option must be an existing file, '%s' does not exist", cmd.getOptionValue('m'))
+ );
+ }
+ System.out.println("metadata file => " + m_metadata.getAbsolutePath());
+ } else {
+ System.out.println("metadata file => no metadata file");
+ }
+ }
+
+ private void readOutputOption(final CommandLine cmd) throws Exception {
+ // Retrieve output file
+ if (cmd.hasOption("o")) {
+ try {
+ m_output = (File) cmd.getParsedOptionValue("o");
+ } catch (ParseException pe) {
+ throw new Exception(
+ format("The output option must be an existing file, '%s' does not exist", cmd.getOptionValue('o'))
+ );
+ }
+ System.out.println("output file => " + m_output.getAbsolutePath());
+ } else {
+ // Inline replacement
+ // We create a temporary file marked by a __ prefix
+ // It will be substituted upon success.
+ m_output = new File("__" + m_input.getName());
+ System.out.println("output file => " + m_input.getAbsolutePath());
+ }
+ }
+
+ private void readInputOption(final CommandLine cmd) throws Exception {
+ // Check that the input file exist
+ m_input = (File) cmd.getParsedOptionValue("i");
+ if (m_input == null || !m_input.isFile()) {
+ throw new Exception(
+ format("The input option must be an existing file, '%s' does not exist", cmd.getOptionValue('i'))
+ );
+ }
+ System.out.println("input file => " + m_input.getAbsolutePath());
+ }
+
+ private void manipulate() {
+ m_pojoization = new Pojoization();
+ m_pojoization.pojoization(m_input, m_output, m_metadata);
+ }
+
+ private void printStatus() {
+ if (m_pojoization.getErrors().size() != 0) {
+ System.err.println("iPOJO Manipulation failed :");
+ for (String error : m_pojoization.getErrors()) {
+ System.err.println("\t" + error);
+ }
+ System.exit(-1);
+ } else {
+ System.err.println("iPOJO Manipulation successfully completed.");
+ for (String warning : m_pojoization.getWarnings()) {
+ System.err.println(warning);
+ }
+ cleanup();
+ System.exit(0);
+ }
+ }
+
+ /**
+ * Upon success, cleanup temporary files.
+ */
+ private void cleanup() {
+ if (m_output.getName().startsWith("__")) {
+ m_input.delete();
+ m_output.renameTo(m_input);
+ }
+ }
+
+ /**
+ * Print help.
+ * @param options
+ */
+ private static void printHelp(final Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("java -jar org.apache.felix.ipojo.ant-" + Constants.getVersion() + ".jar", options);
+ }
+
+ /**
+ * Builds the option list
+ * @return the options
+ */
+ public static Options buildOptions() {
+ Option input =
+ OptionBuilder.withArgName("input file")
+ .withLongOpt("input")
+ .hasArg()
+ .withDescription("the input jar file")
+ .isRequired(true)
+ .withType(File.class)
+ .create('i');
+
+ Option output =
+ OptionBuilder
+ .withLongOpt("output")
+ .withArgName("output file")
+ .hasArg()
+ .withDescription("the output jar file, if not set the manipulation replaces the input file")
+ .isRequired(false)
+ .withType(File.class)
+ .create('o');
+
+ Option metadata =
+ OptionBuilder
+ .withLongOpt("metadata")
+ .withArgName("metadata file")
+ .hasArg()
+ .withDescription("the XML metadata file")
+ .isRequired(false)
+ .withType(File.class)
+ .create('m');
+
+ Option verbose = new Option("X", "exception", false, "print exception stack trace in case of error");
+
+ Option help =
+ OptionBuilder.withLongOpt("help").withDescription("print this message").create('h');
+
+ return new Options()
+ .addOption(input)
+ .addOption(output)
+ .addOption(metadata)
+ .addOption(verbose)
+ .addOption(help);
+ }
+}
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/constants.properties b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/constants.properties
new file mode 100644
index 0000000..d070319
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/constants.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# This file define the different constant we use in the manipulator. This file is filtered by Maven.
+manipulator.version=${project.version}
+ipojo.import.packages=${ipojo.import.packages}
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
new file mode 100644
index 0000000..d3b15f9
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
@@ -0,0 +1 @@
+org.apache.felix.ipojo.manipulator.metadata.annotation.module.DefaultBindingModule
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/composite.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/composite.xsd
new file mode 100644
index 0000000..f127ddd
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/composite.xsd
@@ -0,0 +1,147 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema elementFormDefault="qualified"
+ targetNamespace="org.apache.felix.ipojo.composite"
+ xmlns="org.apache.felix.ipojo.composite"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ipojo="org.apache.felix.ipojo">
+
+ <xs:import namespace="org.apache.felix.ipojo" schemaLocation="http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"></xs:import>
+ <xs:complexType name="CompositeType">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="subservice" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded">
+ </xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional"></xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean"
+ use="optional">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="subservice" type="SubserviceType" />
+ <xs:element name="provides" type="CompositeProvidesType" />
+
+ <xs:complexType name="CompositeProvidesType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+ <xs:sequence>
+ <xs:element name="delegation" type="DelegationType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+
+ <xs:attribute name="action">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="implement"></xs:enumeration>
+ <xs:enumeration value="export"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="SubserviceType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="action" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="import"></xs:enumeration>
+ <xs:enumeration value="instantiate"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+ <xs:attribute name="context-source" type="xs:string"
+ use="optional">
+ </xs:attribute>
+ <xs:attribute name="scope">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"></xs:enumeration>
+ <xs:enumeration value="composite"></xs:enumeration>
+ <xs:enumeration value="composite+global"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:simpleType name="actionType">
+ <xs:restriction base="xs:string"></xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="CompositePropertyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType" minOccurs="0" maxOccurs="unbounded"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional"></xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="CompositeInstanceType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="component" type="xs:string"
+ use="required">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="instance" type="CompositeInstanceType"></xs:element>
+
+ <xs:element name="composite" type="CompositeType"></xs:element>
+
+ <xs:complexType name="DelegationType">
+ <xs:attribute name="method" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="policy" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="all"></xs:enumeration>
+ <xs:enumeration value="one"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd
new file mode 100644
index 0000000..3c729c9
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd
@@ -0,0 +1,704 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema elementFormDefault="qualified" targetNamespace="org.apache.felix.ipojo"
+ xmlns="org.apache.felix.ipojo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:annotation>
+ <xs:documentation>iPOJO Core XML-Schema. This grammars models iPOJO descriptor using core
+ features. It provides several extensibility mechanism in order to compose this schema with
+ external handlers and other component implementation type such as
+ compositions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:element name="ipojo">
+ <xs:complexType>
+ <xs:annotation>
+ <xs:documentation>iPOJO top level element.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="handler" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The handler declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The instance declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="component" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The component type declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="HandlerType">
+ <xs:annotation>
+ <xs:documentation>Description of the handler.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence maxOccurs="unbounded" minOccurs="0">
+ <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="skip"
+ ></xs:any>
+ </xs:sequence>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The implementation class of the handler. The specified class must
+ implement (direcly or not) the "org.apache.felix.ipojo.Handler"
+ interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="namespace" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The XML namespace of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional" fixed="false">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is not exposed. This allows handler introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="level" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>The start level of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstanceType">
+ <xs:annotation>
+ <xs:documentation>Describes an instance of a component.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>The instance props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="component" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>The name of the instance component type.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The (unique) name of the instance.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The version of the factory to use.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a property of an instance configuration.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="property" type="InstancePropertyType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property. Can be optional if a property is inside a structure.
+ The 'instance.name' property has a special semantic as it will be used as the instance
+ name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Value of the property. Can be null for property containing other
+ props.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property, used to create the adequate object. Supported values
+ are list, array, dictionary and map.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RootElementType"/>
+ <xs:complexType name="ComponentType">
+ <xs:annotation>
+ <xs:documentation>Declares an atomic (i.e. primitive) component type.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="callback" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the method(s) to invoke when the component's state
+ changes.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the component provided service(s). By default, all implemented
+ interfaces are published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the service requirements of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="properties" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the properties of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="controller" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>Lifecycle controller for this component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the name of the component type. This name is used to identify
+ the factory attached to this type. If not specified, the factory name is the
+ implementation class name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Determines if the component type is public or private. A public factory
+ (default) can be used from any bundles.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the implementation class of the component
+ type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is exposed. This allows instance introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immediate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Creates the object of the component implementation type as soon as the
+ component instance becomes valid. The default value is "true" if the component doesn't
+ provide any service, "false" otherwise.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory-method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Factory method called to create POJO objects instead of the constructor.
+ The specified method must be a static method of the implementation class returning an
+ instance of this implementation class. The factory method can receive the bundle context
+ in argument.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Set the version of this component type</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RequiresType">
+ <xs:annotation>
+ <xs:documentation>Description of component services requirements.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="ServiceDependencyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="callback" type="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Service requirement method invocation description. Here can be
+ specified a bind method called when a service appears and an unbind method called
+ when a service disappears.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>The interface describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type
+ of this field is a list, vector, collection and set. This attribute is deprecated, use
+ 'specification'.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The name of the field representing the service dependency in the
+ implementation class.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="nullable" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enable or disable the Nullable pattern on optional service
+ dependencies. By default, Nullable pattern is enabled. If disabled, iPOJO will inject
+ null instead of a Nullable object.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="default-implementation" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the default implementation class for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ default-implementation (nullary constructor) and injects it. The given class must
+ implement the required service interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </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 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="from" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specific service provider. The dependency can only be fulfilled by the
+ component with the matching name, or by the service with a matching
+ PID.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="proxy" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or Disable the proxy injection (on field
+ injection)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="scope" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"/>
+ <xs:enumeration value="composite"/>
+ <xs:enumeration value="composite+global"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Dependency callbacks are used to receive notification when service providers
+ arrive and leave.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Method to call</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" use="required">
+ <xs:annotation>
+ <xs:documentation>Type of callback (bind, unbind, or updated). Bind means that the method
+ will be called when a provider arrives. Unbind means that the method will be called when a
+ provider leaves. Updated means that a service was modified but is still valid for the
+ service dependency.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="bind"/>
+ <xs:enumeration value="unbind"/>
+ <xs:enumeration value="modified"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="CallbackType">
+ <xs:annotation>
+ <xs:documentation>Lifecycle Callback. Allows a POJO to be notified when the instance becomes
+ valid or invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the method to call on the transition.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="transition" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the transition when the callback needs to be
+ invoked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>Lifecycle transition state. "validate" means that the component's
+ instance was invalid and becomes valid, "invalidate" means that the component's intance
+ was valid and becomes invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="validate"/>
+ <xs:enumeration value="invalidate"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ContextType">
+ <xs:annotation>
+ <xs:documentation>Allows injecting the OSGi bundle context into the component.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the method receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the field receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="constructor-parameter" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the index of the parameter (0-based) receiving the bundle
+ context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="context" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the context source.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>iPOJO supports two bundle context 'sources': component and instance. Component
+ is the bundle context of the bundle declaring the component, while instance is the bundle
+ context of the bundle declaring the instance. Obviously, they are the same when the instance
+ is declared in the same bundle as the component. By default, it uses 'component'.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="instance"/>
+ <xs:enumeration value="component"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="provides" type="ProvidesType" id="provides"/>
+ <xs:complexType name="ProvidesType">
+ <xs:annotation>
+ <xs:documentation>Provided service(s) description.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>List of service specific props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="controller" minOccurs="0" maxOccurs="1" type="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Service Controller impacting the current provided
+ service
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Deprecated attribute, use 'specifications' instead of
+ 'interface'
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specifications" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The list of service specifications (i.e. interfaces) to expose. By
+ default, all interfaces implemented by the component implementation class are
+ published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="strategy" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>POJO creation strategy. By default, the POJO object is created once
+ (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi
+ service factory policy (one object object per asking bundle). INSTANCE allows creating one
+ different POJO object per asking instance. Finally, a custom strategy can be used by
+ specifying the qualified name of the class extending CreationPolicy
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-registration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service registration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-unregistration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service unregistration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Defines a service controller.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Field of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Intiail value of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="PropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a component property.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Field of the property</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Setter method of the property. This method is called to inject property
+ value.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Default value of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="mandatory" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as mandatory. A mandatory property MUST receive a value
+ either in the component type description or in the instance configuration. Properties are
+ optional by default.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immutable" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as immutable. An immutable property is inherited by the component
+ instance but the value cannot be overridden.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="callback" type="CallbackType" id="callback"/>
+ <xs:element name="context" type="ContextType" id="context"/>
+ <xs:element name="controller" type="ControllerType" id="controller">
+ <xs:annotation>
+ <xs:documentation/>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="requires" type="RequiresType" id="requires"/>
+ <xs:element name="component" type="ComponentType" id="component"/>
+ <xs:element name="handler" type="HandlerType" id="handler"/>
+ <xs:element name="instance" type="InstanceType" id="instance"/>
+
+ <xs:element name="properties" type="PropertiesType" id="properties"/>
+ <xs:complexType name="PropertiesType">
+ <xs:annotation>
+ <xs:documentation>List of component, instance or service props. This field will receive
+ the property value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>The list of props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="propagation" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Propagation of the component properties to the provided services. If this
+ parameter is set to "true", each time properties are reconfigured, they are propagated to
+ each service published by the component.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="pid" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Unique identifier used to reconfigure components properties (via Managed
+ Services) with the Configuration Admin.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="updated" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Method called when a reconfiguration is done</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ServiceDependencyType">
+ <xs:attribute name="specification" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The specification describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type of
+ this field is a list, vector, collection and set.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="optional" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency optionality</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="aggregate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency cardinality.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="policy" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the binding policy of the dependency. Three policies are supported.
+ The dynamic policy supports service providers dynamism. The static policy freezes the
+ provider set as soon as the dependency is used. The dynamic-priority policy is an
+ extension of the dynamic policy, but providers are ranked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="dynamic"/>
+ <xs:enumeration value="static"/>
+ <xs:enumeration value="dynamic-priority"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="comparator" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The comparator attribute allows specifying the class used to compare
+ providers. This class must implemented the java.util.Comparator class and must support the
+ comparison of service references.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="filter" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>LDAP filter used to filter providers</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>id of the service dependency. The id allows to identify and to refer to
+ this dependency.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ControllerType">
+ <xs:annotation>
+ <xs:documentation>Specifies the lifecycle controller of a component, which allows to validate
+ or invalidate component instances.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the component lifecycle controller field. The type of the
+ specified field must be boolean. Setting the value of the specified field to "true" means
+ the validation of the component instance while setting it to "false" means the
+ invalidation of the component instance.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/event-admin.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/event-admin.xsd
new file mode 100644
index 0000000..d3948e6
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/event-admin.xsd
@@ -0,0 +1,90 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.event"
+ xmlns="org.apache.felix.ipojo.handlers.event"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+
+ <xs:complexType name="PublisherType">
+ <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: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>
+ <xs:element name="subscriber" type="SubscriberType"></xs:element>
+
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/extender-pattern.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/extender-pattern.xsd
new file mode 100644
index 0000000..dc39757
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/extender-pattern.xsd
@@ -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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.extender"
+ xmlns="org.apache.felix.ipojo.extender"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="extender" type="ExtenderType"></xs:element>
+ <xs:complexType name="ExtenderType">
+ <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
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/jmx.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/jmx.xsd
new file mode 100644
index 0000000..09b9509
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/jmx.xsd
@@ -0,0 +1,177 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.jmx"
+ xmlns="org.apache.felix.ipojo.handlers.jmx"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="config" type="JMXType"></xs:element>
+
+ <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: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="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: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: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:annotation>
+ <xs:documentation>Enable or disable attribute change notification sending for this property. If set to "true", 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: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
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/temporal.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/temporal.xsd
new file mode 100644
index 0000000..cecc68b
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/temporal.xsd
@@ -0,0 +1,61 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handler.temporal"
+ xmlns="org.apache.felix.ipojo.handler.temporal"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="requires" type="TemporalServiceDependencyType"></xs:element>
+
+ <xs:complexType name="TemporalServiceDependencyType">
+
+ <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="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The dependency id</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: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:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" use="optional" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>Enables or Disables the proxy injection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specification" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Specifies the looked service specification. This attribute is mandatory when injecting in a Collection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/whiteboard-pattern.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/whiteboard-pattern.xsd
new file mode 100644
index 0000000..0c8ebb2
--- /dev/null
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/whiteboard-pattern.xsd
@@ -0,0 +1,45 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.whiteboard"
+ xmlns="org.apache.felix.ipojo.whiteboard"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="wbp" type="WBPType"></xs:element>
+ <xs:complexType name="WBPType">
+ <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
diff --git a/ipojo/manipulator/manipulator-bom/pom.xml b/ipojo/manipulator/manipulator-bom/pom.xml
new file mode 100644
index 0000000..0a6a8e9
--- /dev/null
+++ b/ipojo/manipulator/manipulator-bom/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Manipulator BOM</name>
+ <packaging>pom</packaging>
+
+ <properties>
+ <asm.version>5.0.2</asm.version>
+ <metadata.version>1.6.0</metadata.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>${asm.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>${metadata.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+</project>
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/pom.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/pom.xml
new file mode 100644
index 0000000..6e44f09
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator.manipulator-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-manipulator-creation-test</artifactId>
+ <name>Apache Felix iPOJO Manipulator ~ Creation IT</name>
+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ASimpleParentClass.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ASimpleParentClass.java
new file mode 100644
index 0000000..32f39c5
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ASimpleParentClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+public class ASimpleParentClass {
+
+ protected String name;
+
+ public ASimpleParentClass() {
+ name = "hello";
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructor.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructor.java
new file mode 100644
index 0000000..bd48932
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructor.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class CallSuperConstructor extends ParentClass {
+
+ public CallSuperConstructor() {
+ super("test");
+ System.out.println("plop");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithBC.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithBC.java
new file mode 100644
index 0000000..d75c223
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithBC.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import org.osgi.framework.BundleContext;
+
+public class CallSuperConstructorWithBC extends ParentClassWithBC {
+
+ public CallSuperConstructorWithBC(BundleContext bc) {
+ super("bc", bc, "bundle");
+ String message = "plop-bc";
+ System.out.println(message);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithNew.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithNew.java
new file mode 100644
index 0000000..68237ba
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperConstructorWithNew.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class CallSuperConstructorWithNew extends ParentClass {
+
+ public CallSuperConstructorWithNew() {
+ super(new StringBuffer("test"));
+ System.out.println("plop");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperSuperConstructorWithNew.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperSuperConstructorWithNew.java
new file mode 100644
index 0000000..38720d6
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallSuperSuperConstructorWithNew.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class CallSuperSuperConstructorWithNew extends ParentClass2 {
+
+ public CallSuperSuperConstructorWithNew() {
+ super(new String("test"));
+ System.out.println("plop");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..01429a2
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructor.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructor.java
new file mode 100644
index 0000000..f932351
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructor.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class NoEmptyConstructor implements CheckService {
+
+
+ private String name;
+
+ public NoEmptyConstructor(final String n) {
+ name = n;
+ }
+
+ public boolean check() {
+ return name != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (name == null) {
+ props.put("name", "NULL");
+ } else {
+ props.put("name", name);
+ }
+ return props;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructorWithParentClass.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructorWithParentClass.java
new file mode 100644
index 0000000..5e8afda
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoEmptyConstructorWithParentClass.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class NoEmptyConstructorWithParentClass extends ASimpleParentClass implements CheckService {
+
+ public NoEmptyConstructorWithParentClass(final String n) {
+ name = n;
+ }
+
+ public boolean check() {
+ return name != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (name == null) {
+ props.put("name", "NULL");
+ } else {
+ props.put("name", name);
+ }
+ return props;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
new file mode 100644
index 0000000..6e4fc9e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+public class ParentClass {
+
+ private String name;
+
+ public ParentClass(final String n) {
+ name = n;
+ }
+
+ public ParentClass(final StringBuffer n) {
+ name = n.toString();
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass2.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass2.java
new file mode 100644
index 0000000..6ea0583
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass2.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class ParentClass2 extends SuperParentClass {
+
+ public ParentClass2(String n) {
+ super(n);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClassWithBC.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClassWithBC.java
new file mode 100644
index 0000000..10fa7ba
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClassWithBC.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import org.osgi.framework.BundleContext;
+
+public class ParentClassWithBC {
+
+ private BundleContext bc;
+
+ public ParentClassWithBC(String foo, BundleContext bc, String bar) {
+ this.bc = bc;
+ System.out.println(foo + " : " + this.bc + "(" + bar + ")");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SeveralConstructors.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SeveralConstructors.java
new file mode 100644
index 0000000..21b825e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SeveralConstructors.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class SeveralConstructors implements CheckService {
+
+
+ private String name;
+
+ public SeveralConstructors(){
+ this("hello world");
+ }
+
+ public SeveralConstructors(final String n) {
+ name = n;
+ }
+
+ public boolean check() {
+ return name != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("name", name);
+ return props;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SuperParentClass.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SuperParentClass.java
new file mode 100644
index 0000000..5609a9c
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SuperParentClass.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+public class SuperParentClass {
+
+ private String name;
+
+ public SuperParentClass(final String n) {
+ System.out.println("Hello from super super !");
+ name = n;
+ }
+
+ public SuperParentClass(final StringBuffer n) {
+ name = n.toString();
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..b8e2d62
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..523ddf3
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..7792aaa
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..67c6d7a
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
new file mode 100644
index 0000000..88a1478
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface Plop {
+
+ Object getPlop();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
new file mode 100644
index 0000000..419962e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
@@ -0,0 +1,76 @@
+/*
+ * 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.services;
+
+public interface PrimitiveManipulationTestService {
+
+ byte getByte();
+ void setByte(byte b);
+
+ short getShort();
+ void setShort(short s);
+
+ int getInt();
+ void setInt(int i);
+
+ long getLong();
+ void setLong(long l);
+
+ float getFloat();
+ void setFloat(float f);
+
+ double getDouble();
+ void setDouble(double d);
+
+ char getChar();
+ void setChar(char c);
+
+ boolean getBoolean();
+ void setBoolean(boolean b);
+
+ // Array types
+ byte[] getBytes();
+ void setBytes(byte[] bs);
+
+ short[] getShorts();
+ void setShorts(short[] ss);
+
+ int[] getInts();
+ void setInts(int is[]);
+
+ long[] getLongs();
+ void setLongs(long[] ls);
+
+ float[] getFloats();
+ void setFloats(float[] fs);
+
+ double[] getDoubles();
+ void setDoubles(double[] ds);
+
+ char[] getChars();
+ void setChars(char[] cs);
+
+ boolean[] getBooleans();
+ void setBooleans(boolean[] bs);
+
+ // This method has been added to test an issue when autoboxing.
+ void setLong(long l, String s);
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/resources/metadata.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..d35922c
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/main/resources/metadata.xml
@@ -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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ >
+ <!-- Simple provider used for manipulation analysis -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-FooProviderType-1" architecture="true">
+ <provides/>
+ </component>
+
+ <!-- Non lazzy service provider, to check instantiation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-ImmediateFooProviderType" immediate="true"
+ architecture="true">
+ <provides/>
+ </component>
+
+ <!-- Type checking different creation policy -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-FooProviderType-1-Sing" factory-method="singleton"
+ architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-FooProviderType-1-Sev" factory-method="several"
+ architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-FooProviderType-1-SingM" factory-method="singleton"
+ architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-FooProviderType-1-SevM" factory-method="several"
+ architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationCreation-ImmediateFooProviderTypeSingleton" immediate="true"
+ factory-method="singleton" architecture="true">
+ <provides/>
+ </component>
+
+
+ <!-- Try calling super constructors -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.CallSuperConstructor" immediate="true"/>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.CallSuperConstructorWithNew" immediate="true"/>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.CallSuperConstructorWithBC" immediate="true"/>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.CallSuperSuperConstructorWithNew"
+ immediate="true"/>
+
+ <!-- Several constructors -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.SeveralConstructors">
+ <provides/>
+ </component>
+ <!-- No Empty constructor -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.NoEmptyConstructor">
+ <provides/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.NoEmptyConstructorWithParentClass">
+ <provides/>
+ </component>
+</ipojo>
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPOJOCreation.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPOJOCreation.java
new file mode 100644
index 0000000..3834a6a
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPOJOCreation.java
@@ -0,0 +1,283 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.FooProviderType1;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Check the different method to create POJO object.
+ */
+public class TestPOJOCreation extends BaseTest {
+
+ private ComponentInstance ci_lazzy;
+ private ComponentInstance ci_immediate;
+ private ComponentInstance ci_immediate_singleton;
+
+ private Architecture lazzyArch;
+ private Architecture immeArch;
+ private Architecture immeArchSing;
+
+
+ private ComponentInstance ci_lazzy_sing;
+ private ComponentInstance ci_lazzy_sev;
+
+ private Architecture lazzyArchSing;
+ private Architecture lazzyArchSev;
+ private ComponentInstance ci_lazzy_singM;
+ private ComponentInstance ci_lazzy_sevM;
+
+ private Architecture lazzyArchSingM;
+ private Architecture lazzyArchSevM;
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+ @Before
+ public void setUp() {
+ String factName = "ManipulationCreation-FooProviderType-1";
+ String compName = "FooProvider-1";
+ ci_lazzy = ipojoHelper.createComponentInstance(factName, compName);
+
+ String factName2 = "ManipulationCreation-ImmediateFooProviderType";
+ String compName2 = "FooProvider-2";
+ ci_immediate = ipojoHelper.createComponentInstance(factName2, compName2);
+
+ String factName3 = "ManipulationCreation-ImmediateFooProviderTypeSingleton";
+ String compName3 = "FooProvider-3";
+ ci_immediate_singleton = ipojoHelper.createComponentInstance(factName3, compName3);
+
+ String factName4 = "ManipulationCreation-FooProviderType-1-Sing";
+ String compName4 = "FooProvider-1-Sing";
+ ci_lazzy_sing = ipojoHelper.createComponentInstance(factName4, compName4);
+
+ String factName5 = "ManipulationCreation-FooProviderType-1-Sev";
+ String compName5 = "FooProvider-1-Sev";
+ ci_lazzy_sev = ipojoHelper.createComponentInstance(factName5, compName5);
+
+ String factName6 = "ManipulationCreation-FooProviderType-1-SingM";
+ String compName6 = "FooProvider-1-SingM";
+ ci_lazzy_singM = ipojoHelper.createComponentInstance(factName6, compName6);
+
+ String factName7 = "ManipulationCreation-FooProviderType-1-SevM";
+ String compName7 = "FooProvider-1-SevM";
+ ci_lazzy_sevM = ipojoHelper.createComponentInstance(factName7, compName7);
+
+ lazzyArch = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName + ")");
+ immeArch = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName2 + ")");
+ immeArchSing = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName3 + ")");
+ lazzyArchSing = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName4 + ")");
+ lazzyArchSev = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName5 + ")");
+ lazzyArchSingM = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName6 + ")");
+ lazzyArchSevM = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + compName7 + ")");
+ }
+
+ public void tearDown() {
+ lazzyArch = null;
+ immeArch = null;
+ immeArchSing = null;
+ lazzyArchSing = null;
+ lazzyArchSev = null;
+ lazzyArchSingM = null;
+ lazzyArchSevM = null;
+ ipojoHelper.dispose();
+ }
+
+ /**
+ * Check lazy creation.
+ */
+ @Test
+ public void testLazyCreation() {
+ assertEquals("Check that no objects are created ", 0, ((PrimitiveInstanceDescription) lazzyArch.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArch.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check lazy and singleton creation.
+ */
+ @Test
+ public void testLazyCreationSingleton() {
+ assertEquals("Check that no objects are created ", 0, ((PrimitiveInstanceDescription) lazzyArchSing.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy_sing.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy_sing.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArchSing.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check lazy and "several" creation.
+ */
+ @Test
+ public void testLazyCreationSeveral() {
+ assertEquals("Check that no objects are created ", 0, ((PrimitiveInstanceDescription) lazzyArchSev.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy_sev.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy_sev.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ FooService fs2 = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertTrue("Check the FooService invocation-2", fs2.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArchSev.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check immediate creation.
+ */
+ @Test
+ public void testImmediateCreation() {
+ assertEquals("Check that one object is created ", 1, ((PrimitiveInstanceDescription) immeArch.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_immediate.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_immediate.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) immeArch.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check bundle context injection.
+ */
+ @Test
+ public void testBundleContext() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ Properties p = fs.fooProps();
+ assertNotNull("Check the bundle context", p.get("context"));
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArch.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Test immediate singleton creation.
+ */
+ @Test
+ public void testImmediateSingletonCreation() {
+ assertEquals("Check that one object is created ", 1, ((PrimitiveInstanceDescription) immeArchSing.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_immediate_singleton.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_immediate_singleton.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) immeArchSing.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check creation through a factory method.
+ * (lazy & singleton creation)
+ */
+ @Test
+ public void testLazyCreationSingletonM() {
+ assertEquals("Check that no objects are created ", 0, ((PrimitiveInstanceDescription) lazzyArchSingM.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy_singM.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy_singM.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ FooService fs2 = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertTrue("Check the FooService invocation", fs2.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArchSingM.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Check creation through a factory method.
+ * (lazy & several creation)
+ */
+ @Test
+ public void testLazyCreationSeveralM() {
+ assertEquals("Check that no objects are created ", 0, ((PrimitiveInstanceDescription) lazzyArchSevM.getInstanceDescription()).getCreatedObjects().length);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy_sevM.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy_sevM.getInstanceName() + " is available", ref);
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation", fs.foo());
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArchSevM.getInstanceDescription()).getCreatedObjects().length);
+ FooService fs2 = (FooService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check the FooService invocation-2", fs2.foo());
+ // Only one object as the getService method is called only once (service factory) despite the policy="method".
+ assertEquals("Check the creation of 1 object", 1, ((PrimitiveInstanceDescription) lazzyArchSevM.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ /**
+ * Test a custom constructor.
+ * Not manipulated.
+ */
+ @Test
+ public void testCustomConstuctor() {
+ FooService fs = new FooProviderType1(0, "foo", bc);
+ Properties props = fs.fooProps();
+ assertEquals("Check bar", 0, ((Integer) props.get("bar")).intValue());
+ assertEquals("Check foo", "foo", props.get("foo"));
+ assertEquals("Check context", bc, props.get("context"));
+ }
+
+ @Test
+ public void testSuperCall() {
+ try {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.CallSuperConstructor");
+ } catch (Throwable e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSuperCallWithNew() {
+ try {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.CallSuperConstructorWithNew");
+ } catch (Throwable e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSuperSuperCallWithNew() {
+ try {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.CallSuperSuperConstructorWithNew");
+ } catch (Throwable e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSuperCallWithBC() {
+ try {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.CallSuperConstructorWithBC");
+ } catch (Throwable e) {
+ fail(e.getMessage());
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConstructor.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConstructor.java
new file mode 100644
index 0000000..ba5e815
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-creation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConstructor.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TestSeveralConstructor extends BaseTest {
+
+ private ComponentInstance ci, ci2, ci3;
+
+ @Before
+ public void setUp() {
+ ci = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.SeveralConstructors");
+ ci2 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.NoEmptyConstructor");
+ ci3 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.NoEmptyConstructorWithParentClass");
+ }
+
+ @Test
+ public void testSeveralConstructor() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci.getInstanceName());
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check assignation", cs.check());
+ String name = (String) cs.getProps().get("name");
+ assertEquals("Check message", "hello world", name);
+ //assertNull("Check message", name);
+ }
+
+ @Test
+ public void testNoEmptyConstructor() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci2.getInstanceName());
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ assertFalse("Check assignation", cs.check());
+ String name = (String) cs.getProps().get("name");
+ assertEquals("Check message", "NULL", name);
+ }
+
+ @Test
+ public void testNoEmptyConstructorWithAParentClass() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci3.getInstanceName());
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref);
+ assertTrue("Check assignation", cs.check()); // super set name to "hello"
+ String name = (String) cs.getProps().get("name");
+ assertEquals("Check message", "hello", name);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/pom.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/pom.xml
new file mode 100644
index 0000000..f113d02
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator.manipulator-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-manipulator-manipulation-metadata-test</artifactId>
+
+ <name>Apache Felix iPOJO Manipulator ~ Metadata IT</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Child.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Child.java
new file mode 100644
index 0000000..9441bee
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Child.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class Child extends Parent {
+
+ public Child(String s) {
+ super(s);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentWithInnerClasses.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentWithInnerClasses.java
new file mode 100644
index 0000000..7eb4dbd
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentWithInnerClasses.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+/**
+ **
+ * A component containing inner classes.
+ */
+@Component
+public class ComponentWithInnerClasses{
+
+ public String doSomething() {
+ MyInnerWithANativeMethod nat = new MyInnerWithANativeMethod();
+ MyInnerClass inn = new MyInnerClass();
+ Runnable compute = new Runnable() {
+
+ public void run() {
+ // ...
+ }
+ };
+ return "foo";
+ }
+
+ private String foo = "foo";
+
+ private class MyInnerWithANativeMethod {
+
+ public String foo() {
+ return ComponentWithInnerClasses.this.foo;
+ }
+
+ public native void baz();
+
+ }
+
+ public static class MyStaticInnerClass {
+
+ public static String foo() {
+ return "foo";
+ }
+
+ public String bar() {
+ return "bar";
+ }
+
+ public native void baz();
+ }
+
+ private class MyInnerClass {
+ public String foo() {
+ return ComponentWithInnerClasses.this.foo;
+ }
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..fd0e6de
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..87b7304
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc == null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if (m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo" + a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch (RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+ /**
+ * Custom constructor.
+ *
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..779fdd6
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if (strProp.equals("foo")) {
+ strProp = "bar";
+ } else {
+ strProp = "foo";
+ }
+ strAProp = new String[]{"foo", "bar", "baz"};
+ intAProp = new int[]{3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java
new file mode 100644
index 0000000..eada5a0
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+
+
+public class Manipulation23Tester implements PrimitiveManipulationTestService {
+
+ // Integer types
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1;
+
+ // Floatting types
+ double d = 1.1;
+ float f = 1.1f;
+
+ // Character
+ char c = 'a';
+
+ // Boolean
+ boolean bool = false;
+
+ // Integer arrays
+ byte[] bs = new byte[]{0, 1, 2};
+ short[] ss = new short[]{0, 1, 2};
+ int[] is = new int[]{0, 1, 2};
+ long[] ls = new long[]{0, 1, 2};
+
+ double[] ds = new double[]{0.0, 1.1, 2.2};
+ float[] fs = new float[]{0.0f, 1.1f, 2.2f};
+
+ char[] cs = new char[]{'a', 'b', 'c'};
+
+ boolean[] bools = new boolean[]{false, true, false};
+
+ public boolean getBoolean() {
+ return bool;
+ }
+
+ public boolean[] getBooleans() {
+ return bools;
+ }
+
+ public byte getByte() {
+ return b;
+ }
+
+ public byte[] getBytes() {
+ return bs;
+ }
+
+ public char getChar() {
+ return c;
+ }
+
+ public char[] getChars() {
+ return cs;
+ }
+
+ public double getDouble() {
+ return d;
+ }
+
+ public double[] getDoubles() {
+ return ds;
+ }
+
+ public float getFloat() {
+ return f;
+ }
+
+ public float[] getFloats() {
+ return fs;
+ }
+
+ public int getInt() {
+ return i;
+ }
+
+ public int[] getInts() {
+ return is;
+ }
+
+ public long getLong() {
+ return l;
+ }
+
+ public long[] getLongs() {
+ return ls;
+ }
+
+ public short getShort() {
+ return s;
+ }
+
+ public short[] getShorts() {
+ return ss;
+ }
+
+ public void setBoolean(boolean b) {
+ this.bool = b;
+ }
+
+ public void setBooleans(boolean[] bs) {
+ this.bools = bs;
+ }
+
+ public void setByte(byte b) {
+ this.b = b;
+ }
+
+ public void setBytes(byte[] bs) {
+ this.bs = bs;
+ }
+
+ public void setChar(char c) {
+ this.c = c;
+ }
+
+ public void setChars(char[] cs) {
+ this.cs = cs;
+ }
+
+ public void setDouble(double d) {
+ this.d = d;
+ }
+
+ public void setDoubles(double[] ds) {
+ this.ds = ds;
+ }
+
+ public void setFloat(float f) {
+ this.f = f;
+ }
+
+ public void setFloats(float[] fs) {
+ this.fs = fs;
+ }
+
+ public void setInt(int i) {
+ this.i = i;
+ }
+
+ public void setInts(int[] is) {
+ this.is = is;
+ }
+
+ public void setLong(long l) {
+ this.l = l;
+ }
+
+ public void setLongs(long[] ls) {
+ this.ls = ls;
+ }
+
+ public void setShort(short s) {
+ this.s = s;
+ }
+
+ public void setShorts(short[] ss) {
+ this.ss = ss;
+ }
+
+ // This method has been added to test an issue when autoboxing.
+ public void setLong(long l, String s) {
+ this.l = l;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Multiconstructor.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Multiconstructor.java
new file mode 100644
index 0000000..06ecb06
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Multiconstructor.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+public class Multiconstructor {
+
+ public Multiconstructor(String s1, String s2) {
+ this(s1, s2, -1);
+ }
+
+ public Multiconstructor(String s1, int s2) {
+ this(s1, "" + s2, s2);
+ }
+
+ public Multiconstructor(String s1, String s2, int i) {
+ //...
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultipleCheckService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultipleCheckService.java
new file mode 100644
index 0000000..5956b40
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultipleCheckService.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Parent.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Parent.java
new file mode 100644
index 0000000..8e721bf
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Parent.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+public class Parent {
+
+ private String s;
+
+ public Parent(String s) {
+ this.s = s;
+ }
+
+ public String getS() {
+ return s;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..b8e2d62
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..523ddf3
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..7792aaa
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..67c6d7a
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
new file mode 100644
index 0000000..88a1478
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface Plop {
+
+ Object getPlop();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
new file mode 100644
index 0000000..419962e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
@@ -0,0 +1,76 @@
+/*
+ * 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.services;
+
+public interface PrimitiveManipulationTestService {
+
+ byte getByte();
+ void setByte(byte b);
+
+ short getShort();
+ void setShort(short s);
+
+ int getInt();
+ void setInt(int i);
+
+ long getLong();
+ void setLong(long l);
+
+ float getFloat();
+ void setFloat(float f);
+
+ double getDouble();
+ void setDouble(double d);
+
+ char getChar();
+ void setChar(char c);
+
+ boolean getBoolean();
+ void setBoolean(boolean b);
+
+ // Array types
+ byte[] getBytes();
+ void setBytes(byte[] bs);
+
+ short[] getShorts();
+ void setShorts(short[] ss);
+
+ int[] getInts();
+ void setInts(int is[]);
+
+ long[] getLongs();
+ void setLongs(long[] ls);
+
+ float[] getFloats();
+ void setFloats(float[] fs);
+
+ double[] getDoubles();
+ void setDoubles(double[] ds);
+
+ char[] getChars();
+ void setChars(char[] cs);
+
+ boolean[] getBooleans();
+ void setBooleans(boolean[] bs);
+
+ // This method has been added to test an issue when autoboxing.
+ void setLong(long l, String s);
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/resources/metadata.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..207d314
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/main/resources/metadata.xml
@@ -0,0 +1,76 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Simple provider used for manipulation analysis -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="ManipulationMetadata-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Provider providing 2 services -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="ManipulationMetadata-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Provider with dynamic property -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="ManipulationMetadata-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="[foo, bar]" />
+ <property name="intAProp" field="intAProp" value="[ 1,2,3]" />
+ </provides>
+ </component>
+
+ <!-- Manipulation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.Manipulation23Tester"
+ name="ManipulationMetadata-PrimitiveManipulationTester" architecture="true">
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.MultipleCheckService"
+ name="ManipulationMetadata-SimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.Child">
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.Multiconstructor">
+ </component>
+</ipojo>
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadata.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadata.java
new file mode 100644
index 0000000..bdb314c
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadata.java
@@ -0,0 +1,295 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+/**
+ * Check manipulation metadata written in the manifest.
+ */
+public class TestManipulationMetadata extends BaseTest {
+
+ @Test
+ public void testGetMetadata() {
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+
+ Element manip = getManipulationForComponent(elem, "ManipulationMetadata-FooProviderType-1");
+ assertNotNull("Check manipulation metadata not null for " + "FooProviderType-1", manip);
+ }
+
+ @Test
+ public void testInterface() {
+ String comp_name = "ManipulationMetadata-FooProviderType-1";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] itf = manip.getElements("Interface");
+ assertEquals("Check interfaces number", itf.length, 1);
+ assertEquals("Check itf name", itf[0].getAttribute("name"), FooService.class.getName());
+ }
+
+ @Test
+ public void testInterfaces() {
+ String comp_name = "ManipulationMetadata-FooBarProviderType-1";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] itf = manip.getElements("Interface");
+ assertEquals("Check interfaces number", itf.length, 2);
+ assertEquals("Check itf name", itf[0].getAttribute("name"), FooService.class.getName());
+ assertEquals("Check itf name", itf[1].getAttribute("name"), BarService.class.getName());
+ }
+
+ @Test
+ public void testFields() {
+ String comp_name = "ManipulationMetadata-FooProviderType-Dyn";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] fields = manip.getElements("field");
+ assertEquals("Check field count " + fields.length, fields.length, 5);
+ /*
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+ */
+
+ Element field;
+
+ field = getFieldFromName(manip, "intProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "intProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int");
+
+ field = getFieldFromName(manip, "strProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "strProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "java.lang.String");
+
+ field = getFieldFromName(manip, "strAProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "strAProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "java.lang.String[]");
+
+ field = getFieldFromName(manip, "intAProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "intAProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int[]");
+
+ field = getFieldFromName(manip, "boolProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "boolProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean");
+ }
+
+ @Test
+ public void testPrimitivesFields() {
+ String comp_name = "ManipulationMetadata-PrimitiveManipulationTester";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] fields = manip.getElements("Field");
+ assertEquals("Check field count", fields.length, 16);
+ /*
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1;
+ double d = 1.1;
+ float f = 1.1f;
+ char c = 'a';
+ boolean bool = false;
+ byte[] bs = new byte[] {0,1,2};
+ short[] ss = new short[] {0,1,2};
+ int[] is = new int[] {0,1,2};
+ long[] ls = new long[] {0,1,2};
+ double[] ds = new double[] {0.0, 1.1, 2.2};
+ float[] fs = new float[] {0.0f, 1.1f, 2.2f};
+ char[] cs = new char[] {'a', 'b', 'c'};
+ boolean[] bools = new boolean[] {false, true, false};
+ */
+ Element field;
+
+ field = getFieldFromName(manip, "b");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "byte");
+ field = getFieldFromName(manip, "s");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "short");
+ field = getFieldFromName(manip, "i");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int");
+ field = getFieldFromName(manip, "l");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "long");
+ field = getFieldFromName(manip, "d");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "double");
+ field = getFieldFromName(manip, "f");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "float");
+ field = getFieldFromName(manip, "c");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "char");
+ field = getFieldFromName(manip, "bool");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean");
+
+ field = getFieldFromName(manip, "bs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "byte[]");
+ field = getFieldFromName(manip, "ss");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "short[]");
+ field = getFieldFromName(manip, "is");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int[]");
+ field = getFieldFromName(manip, "ls");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "long[]");
+ field = getFieldFromName(manip, "ds");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "double[]");
+ field = getFieldFromName(manip, "fs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "float[]");
+ field = getFieldFromName(manip, "cs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "char[]");
+ field = getFieldFromName(manip, "bools");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean[]");
+ }
+
+ @Test
+ public void testNoArgMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "check");
+ assertFalse("Check no args", method.containsAttribute("arguments"));
+ assertEquals("Check return", method.getAttribute("return"), "boolean");
+ }
+
+ @Test
+ public void testOneArgsMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "refBind");
+ assertEquals("Check args", method.getAttribute("arguments"), "{org.osgi.framework.ServiceReference}");
+ assertEquals("Check args count", 1, ParseUtils.parseArrays("{org.osgi.framework.ServiceReference}").length);
+ assertFalse("Check return", method.containsAttribute("return"));
+ }
+
+ @Test
+ public void testTwoArgsMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "doNothing");
+ assertEquals("Check args", method.getAttribute("arguments"), "{java.lang.Object,java.lang.String}");
+ assertEquals("Check args count", 2, ParseUtils.parseArrays("{java.lang.Object,java.lang.String}").length);
+ assertEquals("Check return", method.getAttribute("return"), "java.lang.Object");
+ }
+
+ @Test
+ public void testInnerClasses() {
+ String comp_name = "org.apache.felix.ipojo.runtime.core.components.ComponentWithInnerClasses";
+ Element manipulation = getManipulationForComponent(comp_name);
+ Element[] inners = manipulation.getElements("inner");
+ assertEquals(inners.length, 3);
+
+ Element inner = getInnerClassMetadataByName(inners, "MyInnerWithANativeMethod");
+ Assert.assertNotNull(inner);
+ Assert.assertNotNull(getMethodByName(inner.getElements("method"), "foo"));
+
+ inner = getInnerClassMetadataByName(inners, "MyInnerClass");
+ assertNotNull(inner);
+ assertNotNull(getMethodByName(inner.getElements("method"), "foo"));
+
+ inner = getInnerClassMetadataByName(inners, "1");
+ assertNotNull(inner);
+ assertNotNull(getMethodByName(inner.getElements("method"), "run"));
+ }
+
+ private static Element getInnerClassMetadataByName(Element[] inners, String name) {
+ for (Element element : inners) {
+ if (name.equals(element.getAttribute("name"))) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ private static Element getMethodByName(Element[] methods, String name) {
+ for (Element element : methods) {
+ if (name.equals(element.getAttribute("name"))) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+
+ private Element getManipulationForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for (Element comp : comps) {
+ if (comp.containsAttribute("factory") && comp.getAttribute("factory").equals(comp_name)) {
+ return comp.getElements("manipulation")[0];
+ }
+ if (comp.containsAttribute("name") && comp.getAttribute("name").equals(comp_name)) {
+ return comp.getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ private Element getManipulationForComponent(String comp_name) {
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+ Element manip = getManipulationForComponent(elem, comp_name);
+ assertNotNull("Check manipulation metadata not null for " + comp_name, manip);
+ return manip;
+ }
+
+ private Element getMethodFromName(Element manip, String name) {
+ Element methods[] = manip.getElements("Method");
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].containsAttribute("name") && methods[i].getAttribute("name").equals(name)) {
+ return methods[i];
+ }
+ }
+ fail("Method " + name + " not found");
+ return null;
+ }
+
+ private Element getFieldFromName(Element manip, String name) {
+ Element fields[] = manip.getElements("Field");
+ for (int i = 0; i < fields.length; i++) {
+ if (fields[i].containsAttribute("name") && fields[i].getAttribute("name").equals(name)) {
+ return fields[i];
+ }
+ }
+ fail("Field " + name + " not found");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadataAPI.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadataAPI.java
new file mode 100644
index 0000000..21f3957
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-metadata-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManipulationMetadataAPI.java
@@ -0,0 +1,330 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.*;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.*;
+
+public class TestManipulationMetadataAPI extends BaseTest {
+
+ PojoMetadata FooProviderType1, FooBarProviderType1, FooProviderTypeDyn, PrimitiveManipulationTester, SimpleMultipleCheckServiceProvider;
+
+ @Before
+ public void setUp() {
+ String comp_name = "ManipulationMetadata-FooProviderType-1";
+ FooProviderType1 = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-FooBarProviderType-1";
+ FooBarProviderType1 = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-FooProviderType-Dyn";
+ FooProviderTypeDyn = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-PrimitiveManipulationTester";
+ PrimitiveManipulationTester = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ SimpleMultipleCheckServiceProvider = getManipulationMetadataForComponent(comp_name);
+ }
+
+ @Test
+ public void testGetMetadata() {
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getMetadataForComponent(elem, "ManipulationMetadata-FooProviderType-1");
+ assertNotNull("Check manipulation metadata not null for " + "Manipulation-FooProviderType-1", manip);
+ PojoMetadata mm;
+ try {
+ mm = new PojoMetadata(manip);
+ assertNotNull("Check mm not null", mm);
+ } catch (ConfigurationException e) {
+ fail("The creation of pojo metadata has failed");
+ }
+ }
+
+ @Test
+ public void testInterface() {
+ PojoMetadata manip = FooProviderType1;
+
+ String[] itf = manip.getInterfaces();
+ assertEquals("Check interfaces number", itf.length, 1);
+ assertEquals("Check itf name", itf[0], FooService.class.getName());
+
+ assertTrue("Check Foo Service implementation", manip.isInterfaceImplemented(FooService.class.getName()));
+ assertFalse("Check Bar Service implementation", manip.isInterfaceImplemented(BarService.class.getName()));
+ }
+
+ @Test
+ public void testInterfaces() {
+ PojoMetadata manip = FooBarProviderType1;
+ String[] itf = manip.getInterfaces();
+ assertEquals("Check interfaces number", itf.length, 2);
+ assertEquals("Check itf name", itf[0], FooService.class.getName());
+ assertEquals("Check itf name", itf[1], BarService.class.getName());
+
+ assertTrue("Check Foo Service implementation", manip.isInterfaceImplemented(FooService.class.getName()));
+ assertTrue("Check Bar Service implementation", manip.isInterfaceImplemented(BarService.class.getName()));
+ }
+
+// @Test
+// public void testInnerClasses() {
+// String comp_name = "org.apache.felix.ipojo.runtime.core.components.ComponentWithInnerClasses";
+// PojoMetadata metadata = getManipulationMetadataForComponent(comp_name);
+// assertEquals(metadata.getInnerClasses().length, 3);
+// assertNotNull(metadata.getMethodsFromInnerClass("MyInnerWithANativeMethod"));
+// assertNotNull(
+// getMethodMetadata(metadata.getMethodsFromInnerClass("MyInnerWithANativeMethod"),
+// "foo"));
+//
+// assertNotNull(
+// getMethodMetadata(metadata.getMethodsFromInnerClass("MyInnerClass"),
+// "foo"));
+//
+// assertNotNull(
+// getMethodMetadata(metadata.getMethodsFromInnerClass("1"),
+// "run"));
+// }
+
+ public static MethodMetadata getMethodMetadata(MethodMetadata[] methods, String name) {
+ for (MethodMetadata m : methods) {
+ if (m.getMethodName().equals(name)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testFields() {
+ PojoMetadata manip = FooProviderTypeDyn;
+
+ FieldMetadata[] fields = manip.getFields();
+ assertEquals("Check field count + " + fields.length, fields.length, 5);
+ /*
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+ */
+
+ FieldMetadata field;
+
+ field = manip.getField("intProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "int");
+
+ field = manip.getField("intProp", "int");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+
+ field = manip.getField("intProp", "long");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("strProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "java.lang.String");
+
+ field = manip.getField("strProp", "String");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("strProp", "java.lang.String");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String");
+
+ field = manip.getField("strAProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String[]");
+ assertEquals("Check field reflective type : " + field.getFieldName() + " -> " + FieldMetadata.getReflectionType(field.getFieldType()), FieldMetadata.getReflectionType(field.getFieldType()), "[Ljava.lang.String;");
+
+ field = manip.getField("strAProp", "java.lang.String[]");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String[]");
+
+ field = manip.getField("strAProp", "String[]");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("intAProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+ assertEquals("Check field reflective type : " + field.getFieldName() + " -> " + FieldMetadata.getReflectionType(field.getFieldType()), FieldMetadata.getReflectionType(field.getFieldType()), "[I");
+
+ field = manip.getField("intAProp", "int[]");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+
+ field = manip.getField("intAProp", "String[]");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("boolProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "boolProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "boolean");
+
+ field = manip.getField("boolProp", "boolean");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "boolProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+
+ field = manip.getField("boolProp", "bool");
+ assertNull("Check bad field", field);
+ }
+
+ @Test
+ public void testPrimitivesFields() {
+ PojoMetadata manip = PrimitiveManipulationTester;
+ FieldMetadata[] fields = manip.getFields();
+ assertEquals("Check field count", fields.length, 16);
+
+ FieldMetadata field;
+
+ field = manip.getField("b");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "byte");
+ field = manip.getField("s");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "short");
+ field = manip.getField("i");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+ field = manip.getField("l");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "long");
+ field = manip.getField("d");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "double");
+ field = manip.getField("f");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "float");
+ field = manip.getField("c");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "char");
+ field = manip.getField("bool");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+
+ field = manip.getField("bs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "byte[]");
+ field = manip.getField("ss");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "short[]");
+ field = manip.getField("is");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+ field = manip.getField("ls");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "long[]");
+ field = manip.getField("ds");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "double[]");
+ field = manip.getField("fs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "float[]");
+ field = manip.getField("cs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "char[]");
+ field = manip.getField("bools");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean[]");
+ }
+
+ @Test
+ public void testNoArgMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethod("check");
+ assertEquals("Check no args", method.getMethodArguments().length, 0);
+ assertEquals("Check return", method.getMethodReturn(), "boolean");
+
+ method = manip.getMethod("check", new String[0]);
+ assertEquals("Check no args", method.getMethodArguments().length, 0);
+ assertEquals("Check return", method.getMethodReturn(), "boolean");
+ }
+
+ @Test
+ public void testOneArgsMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethods("refBind")[0];
+ assertEquals("Check args count", method.getMethodArguments().length, 1);
+ assertEquals("Check args", method.getMethodArguments()[0], "org.osgi.framework.ServiceReference");
+ assertEquals("Check return", method.getMethodReturn(), "void");
+
+ method = manip.getMethod("refBind", new String[]{"org.osgi.framework.ServiceReference"});
+ assertEquals("Check args count", method.getMethodArguments().length, 1);
+ assertEquals("Check args", method.getMethodArguments()[0], "org.osgi.framework.ServiceReference");
+ assertEquals("Check return", method.getMethodReturn(), "void");
+ }
+
+ @Test
+ public void testTwoArgsMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethods("doNothing")[0];
+ assertEquals("Check args count", 2, method.getMethodArguments().length);
+ assertEquals("Check args - 1", method.getMethodArguments()[0], "java.lang.Object");
+ assertEquals("Check args - 2", method.getMethodArguments()[1], "java.lang.String");
+ assertEquals("Check return", method.getMethodReturn(), "java.lang.Object");
+
+ method = manip.getMethod("doNothing", new String[]{"java.lang.Object", "java.lang.String"});
+ assertEquals("Check args count", 2, method.getMethodArguments().length);
+ assertEquals("Check args - 1", method.getMethodArguments()[0], "java.lang.Object");
+ assertEquals("Check args - 2", method.getMethodArguments()[1], "java.lang.String");
+ assertEquals("Check return", method.getMethodReturn(), "java.lang.Object");
+ }
+
+ private Element getMetadataForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for (int i = 0; i < comps.length; i++) {
+ if (comps[i].containsAttribute("factory") && comps[i].getAttribute("factory").equals(comp_name)) {
+ return comps[i];
+ }
+ if (comps[i].containsAttribute("name") && comps[i].getAttribute("name").equals(comp_name)) {
+ return comps[i];
+ }
+ }
+ return null;
+ }
+
+ private PojoMetadata getManipulationMetadataForComponent(String comp_name) {
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getMetadataForComponent(elem, comp_name);
+ assertNotNull("Check manipulation metadata not null for " + comp_name, manip);
+ try {
+ return new PojoMetadata(manip);
+ } catch (ConfigurationException e) {
+ fail("The creation of pojo metadata for " + comp_name + " has failed");
+ return null;
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/pom.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/pom.xml
new file mode 100644
index 0000000..c96bfb1
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator.manipulator-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-manipulator-manipulation-test</artifactId>
+
+ <name>Apache Felix iPOJO Manipulator ~ Manipulation IT</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/A123/Manipulation23Tester.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/A123/Manipulation23Tester.java
new file mode 100644
index 0000000..86e52b7
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/A123/Manipulation23Tester.java
@@ -0,0 +1,189 @@
+/*
+ * 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.A123;
+
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+
+
+public class Manipulation23Tester implements PrimitiveManipulationTestService {
+
+
+ // Integer types
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1;
+
+ // Floatting types
+ double d = 1.1;
+ float f = 1.1f;
+
+ // Character
+ char c = 'a';
+
+ // Boolean
+ boolean bool = false;
+
+ // Integer arrays
+ byte[] bs = new byte[]{0, 1, 2};
+ short[] ss = new short[]{0, 1, 2};
+ int[] is = new int[]{0, 1, 2};
+ long[] ls = new long[]{0, 1, 2};
+
+ double[] ds = new double[]{0.0, 1.1, 2.2};
+ float[] fs = new float[]{0.0f, 1.1f, 2.2f};
+
+ char[] cs = new char[]{'a', 'b', 'c'};
+
+ boolean[] bools = new boolean[]{false, true, false};
+
+ public boolean getBoolean() {
+ return bool;
+ }
+
+ public boolean[] getBooleans() {
+ return bools;
+ }
+
+ public byte getByte() {
+ return b;
+ }
+
+ public byte[] getBytes() {
+ return bs;
+ }
+
+ public char getChar() {
+ return c;
+ }
+
+ public char[] getChars() {
+ return cs;
+ }
+
+ public double getDouble() {
+ return d;
+ }
+
+ public double[] getDoubles() {
+ return ds;
+ }
+
+ public float getFloat() {
+ return f;
+ }
+
+ public float[] getFloats() {
+ return fs;
+ }
+
+ public int getInt() {
+ return i;
+ }
+
+ public int[] getInts() {
+ return is;
+ }
+
+ public long getLong() {
+ return l;
+ }
+
+ public long[] getLongs() {
+ return ls;
+ }
+
+ public short getShort() {
+ return s;
+ }
+
+ public short[] getShorts() {
+ return ss;
+ }
+
+ public void setBoolean(boolean b) {
+ this.bool = b;
+ }
+
+ public void setBooleans(boolean[] bs) {
+ this.bools = bs;
+ }
+
+ public void setByte(byte b) {
+ this.b = b;
+ }
+
+ public void setBytes(byte[] bs) {
+ this.bs = bs;
+ }
+
+ public void setChar(char c) {
+ this.c = c;
+ }
+
+ public void setChars(char[] cs) {
+ this.cs = cs;
+ }
+
+ public void setDouble(double d) {
+ this.d = d;
+ }
+
+ public void setDoubles(double[] ds) {
+ this.ds = ds;
+ }
+
+ public void setFloat(float f) {
+ this.f = f;
+ }
+
+ public void setFloats(float[] fs) {
+ this.fs = fs;
+ }
+
+ public void setInt(int i) {
+ this.i = i;
+ }
+
+ public void setInts(int[] is) {
+ this.is = is;
+ }
+
+ public void setLong(long l) {
+ this.l = l;
+ }
+
+ public void setLongs(long[] ls) {
+ this.ls = ls;
+ }
+
+ public void setShort(short s) {
+ this.s = s;
+ }
+
+ public void setShorts(short[] ss) {
+ this.ss = ss;
+ }
+
+ public void setLong(long l, String s) {
+ this.l = l;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Annotation.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Annotation.java
new file mode 100644
index 0000000..e31d52d
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Annotation.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class Annotation {
+
+ @Marker(name = "marker", type = Marker.Type.BAR,
+ sub = @SubMarker(subname = "foo"),
+ arrayOfObjects = {"foo", "bar", "baz"},
+ arrayOfAnnotations = {@SubMarker(subname = "foo")}
+ )
+ @SubMarker(subname = "bar")
+ @Invisible
+ public void doSomething() {
+ System.out.println("Foo ...");
+ }
+
+ @Marker(name = "marker", type = Marker.Type.BAR,
+ sub = @SubMarker(subname = "foo"),
+ arrayOfObjects = {"foo", "bar", "baz"},
+ arrayOfAnnotations = {@SubMarker(subname = "foo")}
+ )
+ @SubMarker(subname = "bar")
+ @Invisible
+ public Annotation() {
+
+ }
+
+ public void doSomethingWithParams(@Marker(name = "marker", type = Marker.Type.BAR,
+ sub = @SubMarker(subname = "foo"),
+ arrayOfObjects = {"foo", "bar", "baz"},
+ arrayOfAnnotations = {@SubMarker(subname = "foo")}) String foo,
+ @Invisible String bar,
+ @bla @SubMarker(subname = "baz") String baz) {
+ System.out.println("Foo ...");
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface bla {
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..87b7304
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc == null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if (m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo" + a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch (RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+ /**
+ * Custom constructor.
+ *
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooServiceImpl.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooServiceImpl.java
new file mode 100644
index 0000000..b3ae226
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooServiceImpl implements FooService {
+
+ public boolean foo() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public Properties fooProps() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean getBoolean() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public double getDouble() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getInt() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public long getLong() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public Boolean getObject() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/HandlerBindingTestComponent.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/HandlerBindingTestComponent.java
new file mode 100644
index 0000000..85e7c7b
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/HandlerBindingTestComponent.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.handlers.Foo;
+import org.apache.felix.ipojo.runtime.core.handlers.IgnoredFoo;
+import org.apache.felix.ipojo.runtime.core.services.HandlerBindingTestService;
+
+/**
+ * User: guillaume
+ * Date: 24/07/13
+ * Time: 12:31
+ */
+@Component
+@Provides
+@Instantiate
+public class HandlerBindingTestComponent implements HandlerBindingTestService {
+
+ @Foo("Bonjour")
+ private String greeting;
+
+ @Foo("Welcome")
+ private String welcome;
+
+ @IgnoredFoo("Ignored")
+ private String ignored;
+
+ @Override
+ public String get(final String name) {
+ if ("greeting".equals(name)) {
+ return greeting;
+ }
+ if ("welcome".equals(name)) {
+ return welcome;
+ }
+ if ("ignored".equals(name)) {
+ return ignored;
+ }
+ throw new IllegalArgumentException(name + " is not valid");
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateComponent.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateComponent.java
new file mode 100644
index 0000000..23ad270
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateComponent.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Stereotype;
+
+/**
+ * User: guillaume
+ * Date: 03/06/13
+ * Time: 11:55
+ */
+@Component
+@Instantiate
+@Provides
+@Stereotype
+@Target(ElementType.TYPE)
+public @interface ImmediateComponent {}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/InnerClasses.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/InnerClasses.java
new file mode 100644
index 0000000..e98f457
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/InnerClasses.java
@@ -0,0 +1,213 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.Job;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Callable;
+
+public class InnerClasses implements CheckService {
+
+ private String privateObject;
+ private int privateInt;
+
+ protected String protectedObject;
+ protected int protectedInt;
+
+ String packageObject;
+ int packageInt;
+
+ public String publicObject;
+ public int publicInt;
+
+ private String nonObject = "not-managed";
+ private int nonInt = 5;
+
+ private static int staticint = 6;
+
+ /**
+ * A fake service.
+ */
+ private Runnable runnable;
+
+ public boolean check() {
+ return true;
+ }
+
+ private static final Callable<Integer> callable = new Callable<Integer>() {
+ public Integer call() {
+ return 1;
+ }
+ };
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("publicInner", new PublicNested().doSomething());
+ props.put("packageInner", new PackageNested().doSomething());
+ props.put("protectedInner", new ProtectedNested().doSomething());
+ props.put("privateInner", new PrivateNested().doSomething());
+ props.put("constructorInner", new ConstructorNested().doSomething());
+ props.put("staticInner", new StaticNested().doSomething());
+ props.put("packageStaticInner", new PackageStaticNested().doSomething());
+ try {
+ props.put("call", callable.call());
+ } catch (Exception e) {
+ // Ignore.
+ }
+
+ Job anonymous = new Job() {
+ public Map doSomething() {
+ Map map = new HashMap();
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ return map;
+ }
+ };
+
+ props.put("anonymous", anonymous.doSomething());
+ props.put("public", new PublicNested());
+
+
+ return props;
+ }
+
+ private class PrivateNested implements Job {
+ public Map doSomething() {
+ Map map = new HashMap();
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ return map;
+ }
+ }
+
+ public class PublicNested implements Job {
+ public Map doSomething() {
+ Map map = new HashMap();
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ return map;
+ }
+ }
+
+ class PackageNested implements Job {
+ public Map doSomething() {
+ Map map = new HashMap();
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ return map;
+ }
+ }
+
+ protected class ProtectedNested implements Job {
+ public Map doSomething() {
+ Map map = new HashMap();
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ return map;
+ }
+ }
+
+ protected static class StaticNested implements Job {
+ private Map map = new HashMap();
+
+ public Map doSomething() {
+ map.put("static", new Boolean(true));
+ map.put("staticint", new Integer(staticint));
+ return map;
+ }
+ }
+
+ static class PackageStaticNested implements Job {
+ private Map map = new HashMap();
+
+ public Map doSomething() {
+ map.put("static", new Boolean(true));
+ map.put("staticint", new Integer(staticint));
+ return map;
+ }
+ }
+
+ protected class ConstructorNested implements Job {
+ Map map = new HashMap();
+ public ConstructorNested() {
+ map.put("publicObject", publicObject);
+ map.put("publicInt", new Integer(publicInt));
+ map.put("packageObject", packageObject);
+ map.put("packageInt", new Integer(packageInt));
+ map.put("protectedObject", protectedObject);
+ map.put("protectedInt", new Integer(protectedInt));
+ map.put("privateObject", privateObject);
+ map.put("privateInt", new Integer(privateInt));
+ map.put("nonObject", nonObject);
+ map.put("nonInt", new Integer(nonInt));
+ }
+
+ public Map doSomething() {
+ return map;
+ }
+ }
+
+
+}
+
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Invisible.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Invisible.java
new file mode 100644
index 0000000..ca9808d
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Invisible.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public @interface Invisible {
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java
new file mode 100644
index 0000000..abaf536
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Manipulation23Tester.java
@@ -0,0 +1,130 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+
+
+public class Manipulation23Tester implements PrimitiveManipulationTestService {
+
+ // Integer types
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1;
+
+ // Floatting types
+ double d = 1.1;
+ float f = 1.1f;
+
+ // Character
+ char c = 'a';
+
+ // Boolean
+ boolean bool = false;
+
+ // Integer arrays
+ byte[] bs = new byte[] {0,1,2};
+ short[] ss = new short[] {0,1,2};
+ int[] is = new int[] {0,1,2};
+ long[] ls = new long[] {0,1,2};
+
+ double[] ds = new double[] {0.0, 1.1, 2.2};
+ float[] fs = new float[] {0.0f, 1.1f, 2.2f};
+
+ char[] cs = new char[] {'a', 'b', 'c'};
+
+ boolean[] bools = new boolean[] {false, true, false};
+
+ public boolean getBoolean() { return bool; }
+
+ public boolean[] getBooleans() { return bools; }
+
+ public byte getByte() { return b; }
+
+ public byte[] getBytes() { return bs; }
+
+ public char getChar() { return c; }
+
+ public char[] getChars() { return cs; }
+
+ public double getDouble() { return d; }
+
+ public double[] getDoubles() { return ds; }
+
+ public float getFloat() { return f; }
+
+ public float[] getFloats() { return fs; }
+
+ public int getInt() { return i; }
+
+ public int[] getInts() { return is; }
+
+ public long getLong() { return l; }
+
+ public long[] getLongs() { return ls; }
+
+ public short getShort() { return s; }
+
+ public short[] getShorts() { return ss; }
+
+ public void setBoolean(boolean b) { this.bool = b; }
+
+ public void setBooleans(boolean[] bs) { this.bools = bs; }
+
+ public void setByte(byte b) { this.b = b; }
+
+ public void setBytes(byte[] bs) { this.bs = bs; }
+
+ public void setChar(char c) { this.c = c; }
+
+ public void setChars(char[] cs) { this.cs = cs; }
+
+ public void setDouble(double d) { this.d = d; }
+
+ public void setDoubles(double[] ds) { this.ds = ds; }
+
+ public void setFloat(float f) { this.f = f; }
+
+ public void setFloats(float[] fs) { this.fs = fs; }
+
+ public void setInt(int i) { this.i = i; }
+
+ public void setInts(int[] is) { this.is = is; }
+
+ public void setLong(long l) { this.l = l; }
+
+ public void setLongs(long[] ls) { this.ls = ls; }
+
+ public void setShort(short s) { this.s = s; }
+
+ public void setShorts(short[] ss) {
+ this.ss = new short[ss.length];
+ for (int i = 0; i < ss.length; i++) {
+ this.ss[i] = ss[i];
+ }
+ }
+
+ // This method has been added to test an issue when autoboxing.
+ public void setLong(long l, String s) {
+ this.l = l;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Marker.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Marker.java
new file mode 100644
index 0000000..c5f6e31
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Marker.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Marker {
+
+ String name();
+
+ String[] arrayOfObjects();
+
+ SubMarker sub();
+
+ SubMarker[] arrayOfAnnotations();
+
+ Type type();
+
+ public enum Type {FOO, BAR, BAZ};
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultiBind.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultiBind.java
new file mode 100644
index 0000000..c28d716
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MultiBind.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Stereotype;
+
+/**
+ * User: guillaume
+ * Date: 03/06/13
+ * Time: 16:09
+ */
+@Bind(
+ aggregate = true,
+ optional = false
+)
+@Stereotype
+@Target(ElementType.METHOD)
+public @interface MultiBind {}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PlopImpl.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PlopImpl.java
new file mode 100644
index 0000000..32e9629
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PlopImpl.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Plop;
+
+//TODO this test requires source compatibility 1.5
+public class PlopImpl implements Plop {
+
+ public String getPlop() {
+ return "plop";
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedBazComponent.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedBazComponent.java
new file mode 100644
index 0000000..83fd0cd
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedBazComponent.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+/**
+ * User: guillaume
+ * Date: 03/06/13
+ * Time: 12:22
+ */
+@ImmediateComponent
+public class StereotypedBazComponent implements BazService {
+ @Override
+ public String hello(final String name) {
+ return "Hello " + name;
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedMultiBind.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedMultiBind.java
new file mode 100644
index 0000000..650d63b
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/StereotypedMultiBind.java
@@ -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.runtime.core.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.architecture.Architecture;
+
+/**
+ * User: guillaume
+ * Date: 03/06/13
+ * Time: 12:22
+ */
+@Component
+public class StereotypedMultiBind {
+
+ @MultiBind
+ public void bindArchitecture(Architecture service) {
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SubMarker.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SubMarker.java
new file mode 100644
index 0000000..89787f3
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SubMarker.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SubMarker {
+
+ String subname();
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Switches.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Switches.java
new file mode 100644
index 0000000..a0787e5
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Switches.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.Color;
+
+import java.util.Properties;
+
+/**
+ * A component checking switch construct with integer and enumeration.
+ */
+public class Switches implements CheckService {
+
+ private static enum Stuff {
+ FOO,
+ BAR
+ }
+
+ private String switchOnInteger(int i) {
+ switch (i) {
+ case 0:
+ return "0";
+ case 1:
+ return "1";
+ case 2:
+ return "2";
+ default:
+ return "3";
+ }
+ }
+
+ private String switchOnEnum(Color color) {
+ switch (color) {
+ case RED:
+ return "RED";
+ case GREEN:
+ return "GREEN";
+ case BLUE:
+ return "BLUE";
+ default:
+ return "COLOR";
+ }
+ }
+
+ private String switchOnStuff(Stuff stuff) {
+ switch (stuff) {
+ case FOO : return "foo";
+ case BAR : return "bar";
+ default: return "";
+ }
+ }
+
+ @Override
+ public boolean check() {
+ return true;
+ }
+
+ @Override
+ public Properties getProps() {
+ Properties properties = new Properties();
+ properties.put("switchOnInteger1", switchOnInteger(1));
+ properties.put("switchOnInteger4", switchOnInteger(4));
+
+ properties.put("switchOnEnumRed", switchOnEnum(Color.RED));
+
+ properties.put("switchOnStuffFoo", switchOnStuff(Stuff.FOO));
+
+ return properties;
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TestTypedList.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TestTypedList.java
new file mode 100644
index 0000000..ad27a98
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TestTypedList.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.List;
+import java.util.Properties;
+
+public class TestTypedList implements CheckService {
+
+ private List<FooService> list;
+
+ public boolean check() {
+ return !list.isEmpty();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (list != null) {
+ props.put("list", list);
+
+ int i = 0;
+ for (FooService fs : list) {
+ props.put(i, fs.foo());
+ i++;
+ }
+ }
+
+ return props;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/nativ/NativeComponent.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/nativ/NativeComponent.java
new file mode 100644
index 0000000..3971ac2
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/nativ/NativeComponent.java
@@ -0,0 +1,46 @@
+/*
+ * 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.nativ;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+/**
+ * Component using a native method.
+ */
+@Component
+@Provides
+public class NativeComponent implements BazService {
+
+ static {
+ System.loadLibrary("foo");
+ }
+
+ /**
+ * Provided by the native library.
+ * @return <code>foo: Test program of JNI.</code>
+ */
+ public native String nativeFoo();
+
+ @Override
+ public String hello(String name) {
+ return nativeFoo();
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/Foo.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/Foo.java
new file mode 100644
index 0000000..79e93d7
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/Foo.java
@@ -0,0 +1,39 @@
+/*
+ * 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.handlers;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.HandlerBinding;
+
+/**
+ * User: guillaume
+ * Date: 24/07/13
+ * Time: 12:10
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+@HandlerBinding("com.acme:foo")
+public @interface Foo {
+ String value();
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/FooHandler.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/FooHandler.java
new file mode 100644
index 0000000..cc86c67
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/FooHandler.java
@@ -0,0 +1,84 @@
+/*
+ * 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.handlers;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.annotations.Handler;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * User: guillaume
+ * Date: 24/07/13
+ * Time: 12:08
+ */
+@Handler(namespace = "com.acme", name = "foo")
+public class FooHandler extends PrimitiveHandler {
+
+ @Override
+ public void configure(final Element metadata, final Dictionary configuration) throws ConfigurationException {
+ Element[] elements = metadata.getElements("foo", "com.acme");
+ for (Element foo : elements) {
+ String value = foo.getAttribute("value");
+ String field = foo.getAttribute("field");
+
+ this.getInstanceManager().register(getPojoMetadata().getField(field, "java.lang.String"),
+ new FixedValueFieldInterceptor(value));
+
+ }
+
+ }
+
+ @Override
+ public Object onGet(final Object pojo, final String fieldName, final Object value) {
+ return value;
+ }
+
+ @Override
+ public void stop() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void start() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ private static class FixedValueFieldInterceptor implements FieldInterceptor {
+ private final String m_value;
+
+ public FixedValueFieldInterceptor(final String value) {
+ m_value = value;
+ }
+
+ @Override
+ public void onSet(final Object pojo, final String fieldName, final Object value) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Object onGet(final Object pojo, final String fieldName, final Object value) {
+ return m_value;
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/IgnoredFoo.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/IgnoredFoo.java
new file mode 100644
index 0000000..ccbff86
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/IgnoredFoo.java
@@ -0,0 +1,40 @@
+/*
+ * 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.handlers;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.HandlerBinding;
+import org.apache.felix.ipojo.annotations.Ignore;
+
+/**
+ * User: guillaume
+ * Date: 24/07/13
+ * Time: 12:10
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+@Ignore
+public @interface IgnoredFoo {
+ String value();
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..b8e2d62
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..523ddf3
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
new file mode 100644
index 0000000..f2d7c6e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+/**
+ * User: guillaume
+ * Date: 03/06/13
+ * Time: 12:23
+ */
+public interface BazService {
+ String hello(String name);
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..7792aaa
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Color.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Color.java
new file mode 100644
index 0000000..086b365
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Color.java
@@ -0,0 +1,30 @@
+/*
+ * 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.services;
+
+/**
+ * An enumeration.
+ */
+public enum Color {
+
+ RED,
+ GREEN,
+ BLUE
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..67c6d7a
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/HandlerBindingTestService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/HandlerBindingTestService.java
new file mode 100644
index 0000000..120d60b
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/HandlerBindingTestService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+/**
+ * User: guillaume
+ * Date: 24/07/13
+ * Time: 12:36
+ */
+public interface HandlerBindingTestService {
+ String get(String name);
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Job.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Job.java
new file mode 100644
index 0000000..fdc4b74
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Job.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public interface Job {
+ public Map doSomething();
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
new file mode 100644
index 0000000..88a1478
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Plop.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface Plop {
+
+ Object getPlop();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
new file mode 100644
index 0000000..419962e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/PrimitiveManipulationTestService.java
@@ -0,0 +1,76 @@
+/*
+ * 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.services;
+
+public interface PrimitiveManipulationTestService {
+
+ byte getByte();
+ void setByte(byte b);
+
+ short getShort();
+ void setShort(short s);
+
+ int getInt();
+ void setInt(int i);
+
+ long getLong();
+ void setLong(long l);
+
+ float getFloat();
+ void setFloat(float f);
+
+ double getDouble();
+ void setDouble(double d);
+
+ char getChar();
+ void setChar(char c);
+
+ boolean getBoolean();
+ void setBoolean(boolean b);
+
+ // Array types
+ byte[] getBytes();
+ void setBytes(byte[] bs);
+
+ short[] getShorts();
+ void setShorts(short[] ss);
+
+ int[] getInts();
+ void setInts(int is[]);
+
+ long[] getLongs();
+ void setLongs(long[] ls);
+
+ float[] getFloats();
+ void setFloats(float[] fs);
+
+ double[] getDoubles();
+ void setDoubles(double[] ds);
+
+ char[] getChars();
+ void setChars(char[] cs);
+
+ boolean[] getBooleans();
+ void setBooleans(boolean[] bs);
+
+ // This method has been added to test an issue when autoboxing.
+ void setLong(long l, String s);
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux32/libfoo.so b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux32/libfoo.so
new file mode 100644
index 0000000..e574158
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux32/libfoo.so
Binary files differ
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux64/libfoo.so b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux64/libfoo.so
new file mode 100644
index 0000000..df86ae3
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/linux64/libfoo.so
Binary files differ
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/mac/libfoo.jnilib b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/mac/libfoo.jnilib
new file mode 100755
index 0000000..6c1e780
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/libs/mac/libfoo.jnilib
Binary files differ
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-java5.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-java5.xml
new file mode 100644
index 0000000..bcb40e1
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-java5.xml
@@ -0,0 +1,50 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <!-- Check duplicate method issue -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.PlopImpl"
+ name="plopimpl">
+ <provides></provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.Manipulation23Tester"
+ name="ManipulationPrimitives5-PrimitiveManipulationTester"
+ architecture="true">
+ <provides />
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Annotation"
+ name="Manipulation-Annotations" />
+
+
+ <!-- Typed list -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooServiceImpl">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TestTypedList" name="TypedList">
+ <provides/>
+ <requires field="list" optional="true"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-primitives.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-primitives.xml
new file mode 100644
index 0000000..305a55b
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata-primitives.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Manipulation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.Manipulation23Tester"
+ name="ManipulationPrimitives-PrimitiveManipulationTester" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Manipulation with numbers -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.A123.Manipulation23Tester"
+ name="ManipulationPrimitives-PrimitiveManipulationTesterA" architecture="true">
+ <provides />
+ </component>
+
+
+</ipojo>
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata.xml b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..3144b88
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/main/resources/metadata.xml
@@ -0,0 +1,61 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Simple provider used for manipulation analysis -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Manipulation-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Non lazzy service provider, to check instantiation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Manipulation-ImmediateFooProviderType" immediate="true"
+ architecture="true">
+ <provides />
+ </component>
+
+ <!-- Nested & Inner classes -->
+ <component name="inners" classname="org.apache.felix.ipojo.runtime.core.components.InnerClasses">
+ <requires field="runnable" optional="true"/>
+ <provides>
+ <property field="privateObject"/>
+ <property field="privateInt"/>
+
+ <property field="protectedObject"/>
+ <property field="protectedInt"/>
+
+ <property field="packageObject"/>
+ <property field="packageInt"/>
+
+ <property field="publicObject"/>
+ <property field="publicInt"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Switches">
+ <provides/>
+ </component>
+</ipojo>
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestAnnotationProcessing.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestAnnotationProcessing.java
new file mode 100644
index 0000000..df3b085
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestAnnotationProcessing.java
@@ -0,0 +1,193 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.components.Marker;
+import org.apache.felix.ipojo.runtime.core.components.SubMarker;
+import org.junit.Before;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestAnnotationProcessing extends BaseTest {
+
+ private Class clazz;
+
+ @Before
+ public void setUp() {
+ try {
+ clazz = bc.getBundle().
+ loadClass("org.apache.felix.ipojo.runtime.core.components.Annotation");
+ } catch (ClassNotFoundException e) {
+ fail("Cannot load the annotation class : " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+ @Test
+ public void testAnnotationOnMethod() {
+ Method method = null;
+ try {
+ method = this.clazz.getMethod("doSomething", new Class[0]);
+ } catch (Exception e) {
+ fail("Cannot find the doSomething method : " + e.getMessage());
+ }
+ assertNotNull("Check method existence", method);
+
+ java.lang.annotation.Annotation[] annotations = method.getDeclaredAnnotations();
+ assertNotNull("Check annotations size - 1", annotations);
+ assertEquals("Check annotations size - 2", 2, annotations.length); // Invisible is not visible
+
+ /*
+ @Marker(name="marker", type=Type.BAR,
+ sub=@SubMarker(subname="foo"),
+ arrayOfObjects={"foo", "bar", "baz"},
+ arrayOfAnnotations= {@SubMarker(subname="foo")}
+ )
+ @SubMarker(subname="bar")
+ @Invisible
+ */
+
+ Marker marker = getMarkerAnnotation(annotations);
+ assertNotNull("Check marker", marker);
+
+ assertEquals("Check marker name", "marker", marker.name());
+ assertEquals("Check marker type", Marker.Type.BAR, marker.type());
+ assertEquals("Check sub marker attribute", "foo", marker.sub().subname());
+ assertEquals("Check objects [0]", "foo", marker.arrayOfObjects()[0]);
+ assertEquals("Check objects [1]", "bar", marker.arrayOfObjects()[1]);
+ assertEquals("Check objects [2]", "baz", marker.arrayOfObjects()[2]);
+ assertEquals("Check annotations[0]", "foo", marker.arrayOfAnnotations()[0].subname());
+
+ SubMarker sub = getSubMarkerAnnotation(annotations);
+ assertNotNull("Check submarker", sub);
+ assertEquals("Check submarker", "bar", sub.subname());
+
+ }
+
+ @Test
+ public void testAnnotationOnConstructor() {
+ Constructor method = null;
+ try {
+ method = clazz.getConstructor(new Class[0]);
+ } catch (Exception e) {
+ fail("Cannot find the constructor method : " + e.getMessage());
+ }
+ assertNotNull("Check method existence", method);
+
+ java.lang.annotation.Annotation[] annotations = method.getDeclaredAnnotations();
+ assertNotNull("Check annotations size - 1", annotations);
+ assertEquals("Check annotations size - 2", 2, annotations.length); // Invisible is not visible
+
+ /*
+ @Marker(name="marker", type=Type.BAR,
+ sub=@SubMarker(subname="foo"),
+ arrayOfObjects={"foo", "bar", "baz"},
+ arrayOfAnnotations= {@SubMarker(subname="foo")}
+ )
+ @SubMarker(subname="bar")
+ @Invisible
+ */
+
+ Marker marker = getMarkerAnnotation(annotations);
+ assertNotNull("Check marker", marker);
+
+ assertEquals("Check marker name", "marker", marker.name());
+ assertEquals("Check marker type", Marker.Type.BAR, marker.type());
+ assertEquals("Check sub marker attribute", "foo", marker.sub().subname());
+ assertEquals("Check objects [0]", "foo", marker.arrayOfObjects()[0]);
+ assertEquals("Check objects [1]", "bar", marker.arrayOfObjects()[1]);
+ assertEquals("Check objects [2]", "baz", marker.arrayOfObjects()[2]);
+ assertEquals("Check annotations[0]", "foo", marker.arrayOfAnnotations()[0].subname());
+
+ SubMarker sub = getSubMarkerAnnotation(annotations);
+ assertNotNull("Check submarker", sub);
+ assertEquals("Check submarker", "bar", sub.subname());
+ }
+
+ @Test
+ public void testParameterAnnotations() {
+ Method method = null;
+ try {
+ method = this.clazz.getMethod("doSomethingWithParams", new Class[]{String.class, String.class, String.class});
+ } catch (Exception e) {
+ fail("Cannot find the doSomethingWithParams method : " + e.getMessage());
+ }
+ assertNotNull("Check method existence", method);
+
+ java.lang.annotation.Annotation[][] annotations = method.getParameterAnnotations();
+ assertNotNull("Check annotations size - 1", annotations);
+ assertEquals("Check annotations size - 3", 3, annotations.length);
+
+ // Check internals
+ // First parameter (foo)
+ java.lang.annotation.Annotation[] fooAnns = annotations[0];
+ assertEquals("Check fooAnns length", 1, fooAnns.length);
+ Marker marker = (Marker) fooAnns[0];
+ assertNotNull("Check marker", marker);
+ assertEquals("Check marker name", "marker", marker.name());
+ assertEquals("Check marker type", Marker.Type.BAR, marker.type());
+ assertEquals("Check sub marker attribute", "foo", marker.sub().subname());
+ assertEquals("Check objects [0]", "foo", marker.arrayOfObjects()[0]);
+ assertEquals("Check objects [1]", "bar", marker.arrayOfObjects()[1]);
+ assertEquals("Check objects [2]", "baz", marker.arrayOfObjects()[2]);
+ assertEquals("Check annotations[0]", "foo", marker.arrayOfAnnotations()[0].subname());
+
+ // Second parameter (bar), no annotation (invisible)
+ java.lang.annotation.Annotation[] barAnns = annotations[1];
+ assertEquals("Check barAnns length", 0, barAnns.length);
+
+ // Third parameter (baz), two annotations
+ java.lang.annotation.Annotation[] bazAnns = annotations[2];
+ System.out.println(Arrays.toString(bazAnns));
+ assertEquals("Check bazAnns length", 2, bazAnns.length);
+ }
+
+ private Marker getMarkerAnnotation(java.lang.annotation.Annotation[] annotations) {
+ for (int i = 0; i < annotations.length; i++) {
+ if (annotations[i].annotationType().getName().equals("org.apache.felix.ipojo.runtime.core.components.Marker")) {
+ return (Marker) annotations[i];
+ }
+ }
+ return null;
+ }
+
+ private SubMarker getSubMarkerAnnotation(java.lang.annotation.Annotation[] annotations) {
+ for (int i = 0; i < annotations.length; i++) {
+ if (annotations[i].annotationType().getName().equals("org.apache.felix.ipojo.runtime.core.components.SubMarker")) {
+ return (SubMarker) annotations[i];
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDuplicateMethods.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDuplicateMethods.java
new file mode 100644
index 0000000..b929a86
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDuplicateMethods.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Plop;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestDuplicateMethods extends BaseTest {
+
+
+ @Test
+ public void testDuplicateMethod() {
+ ipojoHelper.createComponentInstance("plopimpl", "plop");
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Plop.class.getName(), "plop");
+ assertNotNull("Check plop", ref);
+ Plop plop = (Plop) osgiHelper.getServiceObject(ref);
+ Object o = plop.getPlop();
+ assertEquals("Check result", "plop", o);
+ ipojoHelper.dispose();
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExceptionHandling.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExceptionHandling.java
new file mode 100644
index 0000000..1f7ba93
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExceptionHandling.java
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.FooProviderType1;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+/**
+ * Test exception handling. POJO exception must be propagated.
+ */
+public class TestExceptionHandling extends BaseTest {
+
+ private ComponentInstance ci_lazzy;
+
+ private ServiceReference lazzyRef;
+ private ServiceReference immRef;
+
+ @Before
+ public void setUp() {
+ String factName = "Manipulation-FooProviderType-1";
+ String compName = "FooProvider-1";
+ ci_lazzy = ipojoHelper.createComponentInstance(factName, compName);
+
+ String factName2 = "Manipulation-ImmediateFooProviderType";
+ String compName2 = "FooProvider-2";
+ ipojoHelper.createComponentInstance(factName2, compName2);
+
+ lazzyRef = osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + compName + ")");
+ immRef = osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + compName2 + ")");
+
+ assertNotNull("LazzyRef", lazzyRef);
+ assertNotNull("ImmRef", immRef);
+ }
+
+ /**
+ * Check that the exception is correctly propagated.
+ */
+ @Test
+ public void testException() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy.getInstanceName() + " is available", ref);
+ FooProviderType1 fs = (FooProviderType1) osgiHelper.getServiceObject(ref);
+ try {
+ fs.testException();
+ fail("The method must returns an exception");
+ } catch (Exception e) {
+ // OK
+ }
+ }
+
+ /**
+ * Check that the exception is correctly catch by the POJO.
+ */
+ @Test
+ public void testTry() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), ci_lazzy.getInstanceName());
+ assertNotNull("Check that a FooService from " + ci_lazzy.getInstanceName() + " is available", ref);
+ FooProviderType1 fs = (FooProviderType1) osgiHelper.getServiceObject(ref);
+ try {
+ fs.testTry();
+ } catch (Exception e) {
+ fail("The method has returned an exception");
+ }
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGenericList.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGenericList.java
new file mode 100644
index 0000000..c7ae3c2
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGenericList.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestGenericList extends BaseTest {
+
+ ComponentInstance foo1, foo2;
+ ComponentInstance checker;
+
+ @Before
+ public void setUp() {
+ foo1 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.FooServiceImpl", "foo1");
+ foo2 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.FooServiceImpl", "foo2");
+ checker = ipojoHelper.createComponentInstance("TypedList", "checker");
+ foo1.stop();
+ foo2.stop();
+ }
+
+ @Test
+ public void testTypedList() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), checker.getInstanceName());
+ CheckService check = (CheckService) osgiHelper.getServiceObject(ref);
+ assertNotNull("Checker availability", check);
+ // Check without providers
+ assertFalse("Empty list", check.check());
+
+ // Start the first provider
+ foo1.start();
+ assertTrue("List with one element", check.check());
+ Properties props = check.getProps();
+ List<FooService> list = (List<FooService>) props.get("list");
+ assertEquals("Check size - 1", 1, list.size());
+
+ // Start the second provider
+ foo2.start();
+ assertTrue("List with two element", check.check());
+ props = check.getProps();
+ list = (List<FooService>) props.get("list");
+ assertEquals("Check size - 2", 2, list.size());
+
+ // Stop the first one
+ foo1.stop();
+ assertTrue("List with one element (2)", check.check());
+ props = check.getProps();
+ list = (List<FooService>) props.get("list");
+ assertEquals("Check size - 3", 1, list.size());
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGetComponentInstance.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGetComponentInstance.java
new file mode 100644
index 0000000..63998f0
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestGetComponentInstance.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.Pojo;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.*;
+
+/**
+ * Check the getComponentInstance method on a POJO
+ */
+public class TestGetComponentInstance extends BaseTest {
+
+ /**
+ * Check if a pojo can correctly be cast in POJO.
+ * Check the getComponentInstance method.
+ */
+ @Test
+ public void testGetComponentInstance() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
+ String factName = "Manipulation-FooProviderType-1";
+ String compName = "FooProvider-1";
+ ServiceReference ref = null;
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider-1", fact);
+
+ Properties props = new Properties();
+ props.put("instance.name", compName);
+ ComponentInstance ci = null;
+ try {
+ ci = fact.createComponentInstance(props);
+ } catch (Exception e1) {
+ fail(e1.getMessage());
+ }
+
+ assertEquals("Check instance name", compName, ci.getInstanceName());
+
+ // Get a FooService provider
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), compName);
+
+ assertNotNull("FS not available", ref);
+
+ // Get foo object
+ FooService fs = (FooService) osgiHelper.getServiceObject(ref);
+
+ // Cast to POJO
+ Pojo pojo = (Pojo) fs;
+ Field im = fs.getClass().getDeclaredField("__IM");
+ assertNotNull(im);
+ im.setAccessible(true);
+ assertNotNull(im.get(fs));
+
+ Method method = fs.getClass().getMethod("getComponentInstance");
+ assertNotNull(method);
+
+ // GetComponentInstance
+ ComponentInstance instance = pojo.getComponentInstance();
+ assertNotNull(instance);
+ assertEquals("Check component instance name", instance.getInstanceName(), compName);
+ assertEquals("Check component factory name", instance.getFactory().getName(), factName);
+ assertNotNull("Instance description not null", instance.getInstanceDescription());
+ PrimitiveInstanceDescription id = (PrimitiveInstanceDescription) instance.getInstanceDescription();
+ assertTrue("Check instance state", id.getState() == ComponentInstance.VALID);
+ assertEquals("Check created pojo count", id.getCreatedObjects().length, 1);
+ assertEquals("Check instance description name", id.getName(), compName);
+
+ ci.dispose();
+
+ // Check that there is no more FooService
+ ref = osgiHelper.getServiceReference(FooService.class.getName());
+ assertNull("FS available, but component instance stopped", ref);
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestHandlerBindingAndIgnoreAnnotation.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestHandlerBindingAndIgnoreAnnotation.java
new file mode 100644
index 0000000..d70ea33
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestHandlerBindingAndIgnoreAnnotation.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.HandlerBindingTestService;
+import org.junit.Test;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import junit.framework.Assert;
+
+public class TestHandlerBindingAndIgnoreAnnotation extends BaseTest {
+
+ public static final String FACTORY_NAME = "org.apache.felix.ipojo.runtime.core.components.HandlerBindingTestComponent";
+
+ @Test
+ public void testFooHandlerBinding() {
+
+/*
+ HandlerFactory handlerFactory = ipojoHelper.getHandlerFactory("com.acme:foo");
+ assertNotNull(handlerFactory);
+ assertEquals(Factory.VALID, handlerFactory.getState());
+*/
+
+ // verify component's factory is here
+ // verify BazService has been published
+ // --> verify instance has been created
+
+ Factory factory = ipojoHelper.getFactory(FACTORY_NAME);
+ assertNotNull(factory);
+ assertEquals(Factory.VALID, factory.getState());
+
+
+ List<HandlerBindingTestService> services = osgiHelper.getServiceObjects(HandlerBindingTestService.class);
+ assertEquals(1, services.size());
+
+ HandlerBindingTestService baz = services.get(0);
+ assertEquals("Bonjour", baz.get("greeting"));
+ assertEquals("Welcome", baz.get("welcome"));
+ assertNull(baz.get("ignored"));
+ ipojoHelper.dispose();
+ }
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[] {CoreOptions.vmOption("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000")};
+ //return new Option[] {CoreOptions.vmOptions("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000")};
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNativeMethod.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNativeMethod.java
new file mode 100644
index 0000000..5ea6c17
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNativeMethod.java
@@ -0,0 +1,169 @@
+/*
+ * 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;
+
+import aQute.lib.osgi.Constants;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.apache.commons.io.FileUtils.copyInputStreamToFile;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+
+/**
+ * Checks that native methods can still be used in components.
+ */
+public class TestNativeMethod extends BaseTest {
+
+ private static final String NATIVE_CLAUSE = "" +
+ //Mac
+ "libs/mac/libfoo.jnilib;osname=MacOSX;osname=MacOS;processor=x86;processor=x86_64;processor=PowerPC," +
+ // Linux 32 bits
+ "libs/linux64/libfoo.so;processor=x86_64;osname=Linux," +
+ // Linux 64 bits
+ "libs/linux32/libfoo.so;processor=x86;osname=Linux";
+
+ /**
+ * We don't deploy the test bundle, a specific one will be built.
+ * On KF we still deploy the bundle as the probe bundles needs the components and services.
+ */
+ @Override
+ public boolean deployTestBundle() {
+ return isKnopflerfish();
+ }
+
+ public boolean isKnopflerfish() {
+ if (context != null) {
+ return super.isKnopflerfish();
+ } else {
+ String pf = System.getProperty("pax.exam.framework");
+ return pf != null && pf.equalsIgnoreCase("knopflerfish");
+ }
+ }
+
+ @Override
+ protected Option[] getCustomOptions() {
+ // The native bundle cannot be deployed on kf,
+ // just skip
+ if (isKnopflerfish()) {
+ return new Option[0];
+ }
+ return new Option[] {
+ buildBundleWithNativeLibraries()
+ };
+ }
+
+ @Test
+ public void testComponentWithNativeMethod() {
+ if (isKnopflerfish()) {
+ System.out.println("Test not supported on knopflerfish");
+ return;
+ }
+
+ ComponentInstance ci = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components" +
+ ".nativ.NativeComponent");
+
+ BazService baz = osgiHelper.getServiceObject(BazService.class, "(instance.name=" + ci.getInstanceName() +")");
+ assertEquals("foo: Test program of JNI.", baz.hello(""));
+ }
+
+
+ public static Option buildBundleWithNativeLibraries() {
+ File out = new File("target/tested/test-bundle-with-native.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ TinyBundle tested = TinyBundles.bundle();
+
+ // We look inside target/classes to find the class and resources
+ File classes = new File("target/classes");
+ Collection<File> files = FileUtils.listFilesAndDirs(classes, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
+ List<String> exports = new ArrayList<String>();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // By convention we export of .services and .service package
+ if (file.getAbsolutePath().contains("/services") || file.getAbsolutePath().contains("/service")) {
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ String packageName = path.replace('/', '.');
+ exports.add(packageName);
+ }
+ } else {
+ // We need to compute the path
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ try {
+ tested.add(path, file.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ System.out.println(file.getName() + " added to " + path);
+ }
+ }
+
+ // Depending on the the order, the probe bundle may already have detected requirements on components.
+ String clause = "" +
+ "org.apache.felix.ipojo.runtime.core.components, " +
+ "org.apache.felix.ipojo.runtime.core.services, " +
+ "org.apache.felix.ipojo.runtime.core.services.A123";
+ for (String export : exports) {
+ if (export.length() > 0) { export += ", "; }
+ clause += export;
+ }
+
+ System.out.println("Exported packages : " + clause);
+
+ InputStream inputStream = tested
+ .set(Constants.BUNDLE_SYMBOLICNAME, BaseTest.TEST_BUNDLE_SYMBOLIC_NAME + "-with-native")
+ .set(Constants.IMPORT_PACKAGE, "*")
+ .set(Constants.EXPORT_PACKAGE, clause)
+ .set(Constants.BUNDLE_NATIVECODE, NATIVE_CLAUSE)
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources")));
+
+ try {
+ copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the manipulated bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the manipulated bundle");
+ }
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNestedClasses.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNestedClasses.java
new file mode 100644
index 0000000..37d2774
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNestedClasses.java
@@ -0,0 +1,228 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.components.InnerClasses;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestNestedClasses extends BaseTest {
+
+ private ComponentInstance instance;
+ private CheckService service;
+
+ @Before
+ public void setUp() {
+ Properties map = new Properties();
+ map.put("publicObject", "publicObject");
+ map.put("publicInt", new Integer(0));
+ map.put("packageObject", "packageObject");
+ map.put("packageInt", new Integer(1));
+ map.put("protectedObject", "protectedObject");
+ map.put("protectedInt", new Integer(2));
+ map.put("privateObject", "privateObject");
+ map.put("privateInt", new Integer(3));
+ map.put("nonObject", "nonObject");
+ map.put("nonInt", new Integer(4));
+ instance = ipojoHelper.createComponentInstance("inners", map);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check service availability", ref);
+ service = (CheckService) osgiHelper.getServiceObject(ref);
+ }
+
+ @After
+ public void tearDown() {
+ service = null;
+ }
+
+ @Test
+ public void testPrivateInnerClass() {
+ Map data = (Map) service.getProps().get("privateInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testProtectedInnerClass() {
+ Map data = (Map) service.getProps().get("protectedInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testPackageInnerClass() {
+ Map data = (Map) service.getProps().get("packageInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testPublicInnerClass() {
+ Map data = (Map) service.getProps().get("publicInner");
+ assertNotNull("Check data existence", data);
+ System.out.println(data);
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testConstructorInnerClass() {
+ Map data = (Map) service.getProps().get("constructorInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testStaticInnerClass() {
+ Map data = (Map) service.getProps().get("staticInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check static", new Boolean(true), data.get("static"));
+ assertEquals("Check static int", new Integer(6), data.get("staticint"));
+
+ }
+
+ @Test
+ public void testAnonymousClassDeclaredInStaticField() {
+ assertEquals(service.getProps().get("call"), 1);
+ }
+
+ @Test
+ public void testPackageStaticInnerClass() {
+ Map data = (Map) service.getProps().get("packageStaticInner");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check static", new Boolean(true), data.get("static"));
+ assertEquals("Check static int", new Integer(6), data.get("staticint"));
+
+ }
+
+ @Test
+ public void testAnonymousInnerClass() {
+ Map data = (Map) service.getProps().get("anonymous");
+ assertNotNull("Check data existence", data);
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+
+ }
+
+ @Test
+ public void testInnerAccess() {
+ Map map = (Map) service.getProps();
+ assertNotNull("Check map existence", map);
+
+ InnerClasses.PublicNested p = (InnerClasses.PublicNested) map.get("public");
+ Map data = p.doSomething();
+
+ assertEquals("Check public object", "publicObject", data.get("publicObject"));
+ assertEquals("Check public int", new Integer(0), data.get("publicInt"));
+ assertEquals("Check protected object", "protectedObject", data.get("protectedObject"));
+ assertEquals("Check protected int", new Integer(2), data.get("protectedInt"));
+ assertEquals("Check package object", "packageObject", data.get("packageObject"));
+ assertEquals("Check package int", new Integer(1), data.get("packageInt"));
+ assertEquals("Check private object", "privateObject", data.get("privateObject"));
+ assertEquals("Check private int", new Integer(3), data.get("privateInt"));
+ assertEquals("Check non-managed object", "not-managed", data.get("nonObject"));
+ assertEquals("Check non-managed int", new Integer(5), data.get("nonInt"));
+ }
+
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypes.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypes.java
new file mode 100644
index 0000000..84b659b
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypes.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Check the manipulation of primitive type (boxed and unboxed).
+ */
+public class TestPrimitiveTypes extends BaseTest {
+
+ PrimitiveManipulationTestService prim;
+
+ @Before
+ public void setUp() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("ManipulationPrimitives-PrimitiveManipulationTester");
+ assertTrue("check instance state", instance.getState() == ComponentInstance.VALID);
+ prim = (PrimitiveManipulationTestService) osgiHelper.getServiceObject(PrimitiveManipulationTestService.class.getName(), "(instance.name=" + instance.getInstanceName() + ")");
+ assertNotNull("Check prim availability", prim);
+ }
+
+ @After
+ public void tearDown() {
+ prim = null;
+ }
+
+ @Test
+ public void testByte() {
+ assertEquals("Check - 1", prim.getByte(), 1);
+ prim.setByte((byte) 2);
+ assertEquals("Check - 2", prim.getByte(), 2);
+ }
+
+ @Test
+ public void testShort() {
+ assertEquals("Check - 1", prim.getShort(), 1);
+ prim.setShort((short) 2);
+ assertEquals("Check - 2", prim.getShort(), 2);
+ }
+
+ @Test
+ public void testInt() {
+ assertEquals("Check - 1", prim.getInt(), 1);
+ prim.setInt((int) 2);
+ assertEquals("Check - 2", prim.getInt(), 2);
+ }
+
+ @Test
+ public void testLong() {
+ assertEquals("Check - 1", prim.getLong(), 1);
+ prim.setLong((long) 2);
+ assertEquals("Check - 2", prim.getLong(), 2);
+ }
+
+ @Test
+ public void testFloat() {
+ assertEquals("Check - 1", prim.getFloat(), 1.1f, 0);
+ prim.setFloat(2.2f);
+ assertEquals("Check - 2", prim.getFloat(), 2.2f, 0);
+ }
+
+ @Test
+ public void testDouble() {
+ assertEquals("Check - 1", prim.getDouble(), 1.1, 0);
+ prim.setDouble(2.2);
+ assertEquals("Check - 2", prim.getDouble(), 2.2, 0);
+ }
+
+ @Test
+ public void testBoolean() {
+ assertFalse("Check - 1", prim.getBoolean());
+ prim.setBoolean(true);
+ assertTrue("Check - 2", prim.getBoolean());
+ }
+
+ @Test
+ public void testChar() {
+ assertEquals("Check - 1", prim.getChar(), 'a');
+ prim.setChar('b');
+ assertEquals("Check - 2", prim.getChar(), 'b');
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypesWithNumberInNames.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypesWithNumberInNames.java
new file mode 100644
index 0000000..28cc0e7
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPrimitiveTypesWithNumberInNames.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Check the manipulation of primitive type (boxed and unboxed).
+ * The targeted implementation contains numbers in the package and class name.
+ */
+public class TestPrimitiveTypesWithNumberInNames extends BaseTest {
+
+ PrimitiveManipulationTestService prim;
+
+ @Before
+ public void setUp() {
+ ComponentInstance instance =
+ ipojoHelper.createComponentInstance("ManipulationPrimitives-PrimitiveManipulationTesterA");
+ assertTrue("check instance state", instance.getState() == ComponentInstance.VALID);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(PrimitiveManipulationTestService.class.getName(),
+ instance.getInstanceName());
+ assertNotNull("Check prim availability", ref);
+ prim = (PrimitiveManipulationTestService) osgiHelper.getServiceObject(ref);
+ }
+
+ @After
+ public void tearDown() {
+ prim = null;
+ }
+
+ @Test
+ public void testByte() {
+ assertEquals("Check - 1", prim.getByte(), 1);
+ prim.setByte((byte) 2);
+ assertEquals("Check - 2", prim.getByte(), 2);
+ }
+
+ @Test
+ public void testShort() {
+ assertEquals("Check - 1", prim.getShort(), 1);
+ prim.setShort((short) 2);
+ assertEquals("Check - 2", prim.getShort(), 2);
+ }
+
+ @Test
+ public void testInt() {
+ assertEquals("Check - 1", prim.getInt(), 1);
+ prim.setInt((int) 2);
+ assertEquals("Check - 2", prim.getInt(), 2);
+ }
+
+ @Test
+ public void testLong() {
+ assertEquals("Check - 1", prim.getLong(), 1);
+ prim.setLong((long) 2);
+ assertEquals("Check - 2", prim.getLong(), 2);
+ }
+
+ @Test
+ public void testFloat() {
+ assertEquals("Check - 1", prim.getFloat(), 1.1f, 0);
+ prim.setFloat(2.2f);
+ assertEquals("Check - 2", prim.getFloat(), 2.2f, 0);
+ }
+
+ @Test
+ public void testDouble() {
+ assertEquals("Check - 1", prim.getDouble(), 1.1, 0);
+ prim.setDouble(2.2);
+ assertEquals("Check - 2", prim.getDouble(), 2.2, 0);
+ }
+
+ @Test
+ public void testBoolean() {
+ assertFalse("Check - 1", prim.getBoolean());
+ prim.setBoolean(true);
+ assertTrue("Check - 2", prim.getBoolean());
+ }
+
+ @Test
+ public void testChar() {
+ assertEquals("Check - 1", prim.getChar(), 'a');
+ prim.setChar('b');
+ assertEquals("Check - 2", prim.getChar(), 'b');
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStereotypeAnnotation.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStereotypeAnnotation.java
new file mode 100644
index 0000000..c956eda
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStereotypeAnnotation.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import junit.framework.Assert;
+
+public class TestStereotypeAnnotation extends BaseTest {
+
+ public static final String BAZ_FACTORY_NAME = "org.apache.felix.ipojo.runtime.core.components.StereotypedBazComponent";
+
+ public static final String MB_FACTORY_NAME = "org.apache.felix.ipojo.runtime.core.components.StereotypedMultiBind";
+
+ @Test
+ public void testTypeStereotype() {
+
+ // verify component's factory is here
+ // verify BazService has been published
+ // --> verify instance has been created
+
+ Factory factory = ipojoHelper.getFactory(BAZ_FACTORY_NAME);
+ Assert.assertNotNull(factory);
+ assertEquals(Factory.VALID, factory.getState());
+
+
+ List<BazService> services = osgiHelper.getServiceObjects(BazService.class);
+ assertEquals(1, services.size());
+
+ BazService baz = services.get(0);
+ assertEquals("Hello Guillaume", baz.hello("Guillaume"));
+ ipojoHelper.dispose();
+ }
+
+ @Test
+ public void testMethodStereotype() {
+
+ // verify component's factory is here
+ // verify that the requires handler has been activated
+ // verify that a created instance works
+
+ Factory factory = ipojoHelper.getFactory(MB_FACTORY_NAME);
+ Assert.assertNotNull(factory);
+ assertEquals(Factory.VALID, factory.getState());
+
+ assertTrue(factory.getRequiredHandlers().contains("org.apache.felix.ipojo:requires"));
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance(MB_FACTORY_NAME, "stereotype-multibind-instance");
+ assertTrue(ipojoHelper.isInstanceValid(instance));
+
+ ipojoHelper.dispose();
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSwitches.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSwitches.java
new file mode 100644
index 0000000..c4c879e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSwitches.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.ProbeBuilder;
+import org.ops4j.pax.exam.TestProbeBuilder;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestSwitches extends BaseTest {
+
+ private ComponentInstance instance;
+ private CheckService service;
+
+ @Before
+ public void setUp() {
+ instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.components.Switches");
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check service availability", ref);
+ service = (CheckService) osgiHelper.getServiceObject(ref);
+ }
+
+ @After
+ public void tearDown() {
+ service = null;
+ }
+
+ @ProbeBuilder
+ public TestProbeBuilder probe(TestProbeBuilder builder) {
+ builder.setHeader(Constants.IMPORT_PACKAGE, "org.osgi.framework, org.apache.felix.ipojo, " +
+ "org.ow2.chameleon.testing.helpers," +
+ "org.apache.felix.ipojo.architecture, org.apache.felix.ipojo.handlers.dependency," +
+ "org.apache.felix.ipojo.runtime.core.services, org.apache.felix.ipojo.runtime.core.components");
+ builder.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "org.ops4j.pax.exam,org.junit,javax.inject," +
+ "org.ops4j.pax.exam.options,junit.framework");
+ builder.setHeader("Bundle-ManifestVersion", "2");
+ return builder;
+ }
+
+ @Test
+ public void testSwitches() {
+ Properties properties = service.getProps();
+ assertEquals(properties.get("switchOnInteger1"), "1");
+ assertEquals(properties.get("switchOnInteger4"), "3");
+
+
+ assertEquals(properties.get("switchOnEnumRed"), "RED");
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestTypeBoxing.java b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestTypeBoxing.java
new file mode 100644
index 0000000..8a6732e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/ipojo-manipulator-manipulation-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestTypeBoxing.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.PrimitiveManipulationTestService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestTypeBoxing extends BaseTest {
+
+ ComponentInstance instance; // Instance under test
+
+ PrimitiveManipulationTestService prim;
+
+ ServiceReference prim_ref;
+
+ @Before
+ public void setUp() {
+ Properties p1 = new Properties();
+ p1.put("instance.name", "primitives");
+ instance = ipojoHelper.createComponentInstance("ManipulationPrimitives5-PrimitiveManipulationTester", p1);
+ assertTrue("check instance state", instance.getState() == ComponentInstance.VALID);
+ prim_ref = ipojoHelper.getServiceReferenceByName(PrimitiveManipulationTestService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check prim availability", prim_ref);
+ prim = (PrimitiveManipulationTestService) osgiHelper.getServiceObject(prim_ref);
+ }
+
+ @After
+ public void tearDown() {
+ prim = null;
+ }
+
+
+ @Test
+ public void testLongFromObject() {
+ assertEquals("Check - 1", prim.getLong(), 1);
+ Long l = new Long(2);
+ prim.setLong(l);
+ assertEquals("Check - 2", prim.getLong(), 2);
+ }
+
+ @Test
+ public void testLongFromObject2() {
+ assertEquals("Check - 1", prim.getLong(), 1);
+ Long l = new Long(2);
+ prim.setLong(l, "ss");
+ assertEquals("Check - 2", prim.getLong(), 2);
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList("org.apache.felix.ipojo.runtime.core.components");
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/pom.xml b/ipojo/manipulator/manipulator-it/online-manipulator-it/pom.xml
new file mode 100644
index 0000000..5746a2e
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator.manipulator-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-online-manipulator-test</artifactId>
+
+ <name>Apache Felix iPOJO Manipulator ~ Online IT</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/Consumer.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/Consumer.java
new file mode 100644
index 0000000..0549286
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/Consumer.java
@@ -0,0 +1,36 @@
+/*
+ * 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.online.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.test.online.services.Hello;
+
+@Component
+public class Consumer {
+
+ @Requires
+ private Hello hello;
+
+ public Consumer() {
+ System.out.println(hello.sayHello());
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/FrenchHelloService.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/FrenchHelloService.java
new file mode 100644
index 0000000..289f3e9
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/FrenchHelloService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.online.components;
+
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.test.online.module.Type;
+import org.apache.felix.ipojo.test.online.services.Hello;
+
+/**
+ * User: guillaume
+ * Date: 27/02/2014
+ * Time: 14:33
+ */
+@Type
+@Instantiate
+@Provides
+public class FrenchHelloService implements Hello {
+ @Override
+ public String sayHello() {
+ return "Bonjour";
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/GermanHelloService.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/GermanHelloService.java
new file mode 100644
index 0000000..a4cd6d5
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/GermanHelloService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.online.components;
+
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.test.online.module.Type2;
+import org.apache.felix.ipojo.test.online.services.Hello;
+
+/**
+ * User: guillaume
+ * Date: 27/02/2014
+ * Time: 14:33
+ */
+@Type2
+@Instantiate
+@Provides
+public class GermanHelloService implements Hello {
+ @Override
+ public String sayHello() {
+ return "Hallo";
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProvider.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProvider.java
new file mode 100644
index 0000000..d2ef530
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProvider.java
@@ -0,0 +1,31 @@
+/*
+ * 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.online.components;
+
+
+import org.apache.felix.ipojo.test.online.services.Hello;
+
+public class MyProvider implements Hello {
+
+ public String sayHello() {
+ return "Hello";
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProviderWithAnnotations.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProviderWithAnnotations.java
new file mode 100644
index 0000000..a7c7312
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/components/MyProviderWithAnnotations.java
@@ -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.online.components;
+
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.test.online.services.Hello;
+
+@Component
+@Provides
+@Instantiate
+public class MyProviderWithAnnotations implements Hello {
+
+ public String sayHello() {
+ return "Hello";
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Activator.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Activator.java
new file mode 100644
index 0000000..8bf3d80
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Activator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.online.module;
+
+import org.apache.felix.ipojo.manipulator.spi.Module;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * User: guillaume
+ * Date: 27/02/2014
+ * Time: 14:31
+ */
+public class Activator implements BundleActivator {
+
+ private ServiceRegistration<Module> registration;
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ registration = context.registerService(Module.class, new TypeModule(), null);
+ }
+
+ @Override
+ public void stop(final BundleContext context) throws Exception {
+ registration.unregister();
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type.java
new file mode 100644
index 0000000..2329851
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type.java
@@ -0,0 +1,36 @@
+/*
+ * 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.online.module;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Stereotype;
+
+/**
+ * Stereotype defined in a Module
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Type {
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type2.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type2.java
new file mode 100644
index 0000000..36992ab
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/Type2.java
@@ -0,0 +1,38 @@
+/*
+ * 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.online.module;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Stereotype;
+
+/**
+ * Annotated stereotype
+ */
+@Stereotype
+@Component
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Type2 {
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/TypeModule.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/TypeModule.java
new file mode 100644
index 0000000..877d163
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/module/TypeModule.java
@@ -0,0 +1,84 @@
+/*
+ * 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.online.module;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationLiteral;
+import org.apache.felix.ipojo.manipulator.spi.AbsBindingModule;
+
+/**
+ * User: guillaume
+ * Date: 27/02/2014
+ * Time: 14:26
+ */
+public class TypeModule extends AbsBindingModule {
+ @Override
+ public void configure() {
+ // @Type is equivalent to @Component
+ bindStereotype(Type.class)
+ .with(new ComponentLiteral());
+ }
+
+ public static class ComponentLiteral extends AnnotationLiteral<Component> implements Component {
+
+ public boolean public_factory() {
+ return true;
+ }
+
+ public boolean publicFactory() {
+ return true;
+ }
+
+ public String name() {
+ return "";
+ }
+
+ public boolean architecture() {
+ return false;
+ }
+
+ public boolean immediate() {
+ return false;
+ }
+
+ public boolean propagation() {
+ return true;
+ }
+
+ public String managedservice() {
+ return "";
+ }
+
+ public String factory_method() {
+ return "";
+ }
+
+ public String factoryMethod() {
+ return "";
+ }
+
+ public String version() {
+ return "";
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/services/Hello.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/services/Hello.java
new file mode 100644
index 0000000..a58fb1f
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/java/org/apache/felix/ipojo/test/online/services/Hello.java
@@ -0,0 +1,26 @@
+/*
+ * 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.online.services;
+
+public interface Hello {
+
+ public String sayHello();
+
+}
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/consumer.xml b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/consumer.xml
new file mode 100644
index 0000000..a78ad3c
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/consumer.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<instance component="org.apache.felix.ipojo.test.online.components.Consumer"/>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/provider.xml b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/provider.xml
new file mode 100644
index 0000000..593779f
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/main/resources/provider.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<component classname="org.apache.felix.ipojo.test.online.components.MyProvider">
+ <provides/>
+</component>
+<instance component="org.apache.felix.ipojo.test.online.components.MyProvider"/>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator-it/online-manipulator-it/src/test/java/org/apache/felix/ipojo/test/online/OnlineManipulatorTest.java b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/test/java/org/apache/felix/ipojo/test/online/OnlineManipulatorTest.java
new file mode 100644
index 0000000..63b9ebc
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/online-manipulator-it/src/test/java/org/apache/felix/ipojo/test/online/OnlineManipulatorTest.java
@@ -0,0 +1,593 @@
+/*
+ * 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.online;
+
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.test.online.components.Consumer;
+import org.apache.felix.ipojo.test.online.components.FrenchHelloService;
+import org.apache.felix.ipojo.test.online.components.GermanHelloService;
+import org.apache.felix.ipojo.test.online.components.MyProvider;
+import org.apache.felix.ipojo.test.online.components.MyProviderWithAnnotations;
+import org.apache.felix.ipojo.test.online.module.Activator;
+import org.apache.felix.ipojo.test.online.module.Type;
+import org.apache.felix.ipojo.test.online.module.Type2;
+import org.apache.felix.ipojo.test.online.module.TypeModule;
+import org.apache.felix.ipojo.test.online.services.Hello;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.io.StreamUtils;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.InnerClassStrategy;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.*;
+import org.osgi.service.url.URLStreamHandlerService;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class OnlineManipulatorTest {
+
+
+ private static File TMP = new File("target/tmp-bundle");
+
+ @Inject
+ BundleContext context;
+
+ private OSGiHelper helper;
+
+
+ @Configuration
+ public Option[] configure() throws IOException {
+ Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(Level.INFO);
+
+ String providerWithMetadata = providerWithMetadata();
+ String providerWithMetadataInMetaInf = providerWithMetadataInMetaInf();
+ String providerWithoutMetadata = providerWithoutMetadata();
+ String consumerWithMetadata = consumerWithMetadata();
+ String consumerWithoutMetadata = consumerWithoutMetadata();
+ String providerUsingModules = providerUsingModules();
+ String providerUsingAnnotatedStereotype = providerUsingAnnotatedStereotype();
+
+ return options(
+ cleanCaches(),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo").versionAsInProject(),
+ mavenBundle("org.ow2.chameleon.testing", "osgi-helpers").versionAsInProject(),
+ mavenBundle("org.apache.felix","org.apache.felix.ipojo.manipulator.online").versionAsInProject(),
+ junitBundles(),
+
+ provision(
+ TinyBundles.bundle()
+ .add(Hello.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build(),
+ moduleBundle()
+ ),
+
+ systemProperty("providerWithMetadata").value(providerWithMetadata),
+ systemProperty("providerWithMetadataInMetaInf").value(providerWithMetadataInMetaInf),
+ systemProperty("providerWithoutMetadata").value(providerWithoutMetadata),
+ systemProperty("providerUsingAnnotations").value(providerUsingAnnotation()),
+ systemProperty("consumerWithMetadata").value(consumerWithMetadata),
+ systemProperty("consumerWithoutMetadata").value(consumerWithoutMetadata),
+ systemProperty("providerUsingModules").value(providerUsingModules),
+ systemProperty("providerUsingAnnotatedStereotype").value(providerUsingAnnotatedStereotype),
+
+ systemProperty("org.knopflerfish.osgi.registerserviceurlhandler").value("true")
+ );
+
+ }
+
+ private InputStream moduleBundle() {
+ return TinyBundles.bundle()
+ .add(Activator.class)
+ .add(Type.class)
+ .add(Type2.class)
+ .add(TypeModule.class, InnerClassStrategy.ALL)
+ .add(TypeModule.ComponentLiteral.class)
+ .set(Constants.BUNDLE_ACTIVATOR, Activator.class.getName())
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Manipulator Module")
+ .set(Constants.IMPORT_PACKAGE,
+ "org.osgi.framework," +
+ "org.apache.felix.ipojo.manipulator.spi," +
+ "org.apache.felix.ipojo.annotations")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.test.online.module")
+ .build();
+ }
+
+ @Before
+ public void before() {
+ helper = new OSGiHelper(context);
+ waitForStability(context);
+
+ helper.waitForService(URLStreamHandlerService.class, null, 1000);
+
+ Assert.assertEquals("Check online manipulator bundle state",
+ helper.getBundle("org.apache.felix.ipojo.manipulator.online").getState(),
+ Bundle.ACTIVE);
+
+ URLStreamHandlerService svc = helper.getServiceObject(URLStreamHandlerService.class, null);
+ Assert.assertNotNull("URL Stream handler exported", svc);
+ System.out.println(svc);
+ }
+
+ @After
+ public void after() {
+ helper.dispose();
+ }
+
+ private static File getTemporaryFile(String name) throws IOException {
+ if (!TMP.exists()) {
+ TMP.mkdirs();
+ TMP.deleteOnExit();
+ }
+ File file = File.createTempFile(name, ".jar", TMP);
+ //File file = new File(TMP, name + ".jar");
+ if (file.exists()) {
+ file.delete();
+ }
+ file.deleteOnExit();
+ return file;
+ }
+
+ @Test
+ public void installProviderWithMetadata1() throws Exception {
+ String url = context.getProperty("providerWithMetadata");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+
+ assertBundle("Provider");
+
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+ }
+
+
+ @Test
+ public void installProviderWithMetadata2() throws BundleException, InvalidSyntaxException, IOException {
+ String url = context.getProperty("providerWithMetadataInMetaInf");
+ Assert.assertNotNull(url);
+ System.out.println("prefixed url : " + "ipojo:" + url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+ assertBundle("Provider");
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+ }
+
+ @Test
+ public void installProviderWithoutMetadata() throws BundleException, InvalidSyntaxException, IOException {
+ String url = context.getProperty("providerWithoutMetadata");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+
+ assertBundle("Provider");
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+ }
+
+ @Test
+ public void installProviderUsingAnnotations() throws BundleException, InvalidSyntaxException, IOException {
+ String url = context.getProperty("providerUsingAnnotations");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+
+ assertBundle("Provider-with-annotations");
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+ }
+
+ @Test
+ public void installConsumerWithMetadata() throws BundleException, InvalidSyntaxException, IOException {
+ String url = context.getProperty("providerWithoutMetadata");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+ assertBundle("Provider");
+
+ String url2 = context.getProperty("consumerWithMetadata");
+ Assert.assertNotNull(url);
+ Bundle bundle2 = context.installBundle("ipojo:" + url2);
+ bundle2.start();
+
+ assertBundle("Consumer");
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ // Wait for activation.
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+ bundle.uninstall();
+ bundle2.uninstall();
+ }
+
+ @Test
+ public void installConsumerWithoutMetadata() throws BundleException, InvalidSyntaxException, IOException {
+ String url = context.getProperty("providerWithMetadataInMetaInf");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+ assertBundle("Provider");
+ helper.waitForService(Hello.class.getName(), null, 5000);
+
+ String url2 = context.getProperty("consumerWithoutMetadata");
+ Assert.assertNotNull(url);
+ Bundle bundle2 = context.installBundle("ipojo:" + url2);
+ bundle2.start();
+ assertBundle("Consumer");
+ // Wait for activation.
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ assertValidity();
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+ bundle2.uninstall();
+ }
+
+ @Test
+ public void testManipulatorModuleRegisteredAsServicesAreLoaded() throws Exception {
+
+ String url = context.getProperty("providerUsingModules");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+ assertBundle("ProviderUsingModules");
+
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+
+ }
+
+ @Test
+ public void testAnnotatedStereotypes() throws Exception {
+
+ String url = context.getProperty("providerUsingAnnotatedStereotype");
+ Assert.assertNotNull(url);
+ Bundle bundle = context.installBundle("ipojo:" + url);
+ bundle.start();
+ assertBundle("ProviderUsingAnnotatedStereotype");
+
+ helper.waitForService(Hello.class.getName(), null, 5000);
+ Assert.assertNotNull(context.getServiceReference(Hello.class.getName()));
+
+ bundle.uninstall();
+
+ }
+
+ /**
+ * Gets a regular bundle containing metadata file
+ *
+ * @return the url of the bundle
+ * @throws java.io.IOException
+ */
+ public static String providerWithMetadata() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add("metadata.xml", OnlineManipulatorTest.class.getClassLoader().getResource("provider.xml"))
+ .add(MyProvider.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerWithMetadata");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ return out.toURI().toURL().toExternalForm();
+ }
+
+ /**
+ * Gets a regular bundle containing metadata file in the META-INF directory
+ *
+ * @return the url of the bundle
+ * @throws java.io.IOException
+ */
+ public static String providerWithMetadataInMetaInf() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add("META-INF/metadata.xml", OnlineManipulatorTest.class.getClassLoader().getResource("provider.xml"))
+ .add(MyProvider.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerWithMetadataInMetaInf");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ return out.toURI().toURL().toExternalForm();
+ }
+
+ /**
+ * Gets a provider bundle which does not contain the metadata file.
+ *
+ * @return the url of the bundle + metadata
+ * @throws java.io.IOException
+ */
+ public static String providerWithoutMetadata() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ //.addResource("metadata.xml", this.getClass().getClassLoader().getResource("provider.xml"))
+ .add(MyProvider.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Provider")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerWithoutMetadata");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ String url = out.toURI().toURL().toExternalForm();
+
+ return url + "!" + OnlineManipulatorTest.class.getClassLoader().getResource("provider.xml");
+ }
+
+ /**
+ * Gets a provider bundle which does not contain the metadata file and using annotations.
+ *
+ * @return the url of the bundle without metadata
+ * @throws java.io.IOException
+ */
+ public static String providerUsingAnnotation() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ //.addResource("metadata.xml", this.getClass().getClassLoader().getResource("provider.xml"))
+ .add(MyProviderWithAnnotations.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Provider-with-annotations")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerUsingAnnotations");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ String url = out.toURI().toURL().toExternalForm();
+
+ return url;
+ }
+
+ /**
+ * Gets a consumer bundle using annotation containing the instance
+ * declaration in the metadata.
+ *
+ * @return the url of the bundle
+ * @throws java.io.IOException
+ */
+ public static String consumerWithMetadata() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add("metadata.xml", OnlineManipulatorTest.class.getClassLoader().getResource("consumer.xml"))
+ .add(Consumer.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Consumer")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("consumerWithMetadata");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ return out.toURI().toURL().toExternalForm();
+ }
+
+ /**
+ * Gets a consumer bundle using annotation containing the instance
+ * declaration in the metadata.
+ *
+ * @return the url of the bundle
+ * @throws java.io.IOException
+ */
+ public static String providerUsingModules() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add(FrenchHelloService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderUsingModules")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerUsingModules");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ return out.toURI().toURL().toExternalForm();
+ }
+
+ public static String providerUsingAnnotatedStereotype() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add(GermanHelloService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderUsingAnnotatedStereotype")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("providerUsingAnnotatedStereotype");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ return out.toURI().toURL().toExternalForm();
+ }
+
+ /**
+ * Gets a consumer bundle using annotation that does not contain
+ * metadata
+ *
+ * @return the url of the bundle + metadata
+ * @throws java.io.IOException
+ */
+ public static String consumerWithoutMetadata() throws IOException {
+ InputStream is = TinyBundles.bundle()
+ .add(Consumer.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Consumer")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.test.online.services")
+ .build();
+
+ File out = getTemporaryFile("consumerWithoutMetadata");
+ StreamUtils.copyStream(is, new FileOutputStream(out), true);
+ String url = out.toURI().toURL().toExternalForm();
+
+ return url + "!" + OnlineManipulatorTest.class.getClassLoader().getResource("consumer.xml");
+ }
+
+
+ public void dumpServices() throws InvalidSyntaxException {
+ ServiceReference[] refs = context.getAllServiceReferences(null, null);
+ System.out.println(" === Services === ");
+ for (ServiceReference ref : refs) {
+ String[] itf = (String[]) ref.getProperty(Constants.OBJECTCLASS);
+ System.out.println(itf[0]);
+ }
+ System.out.println("====");
+ }
+
+ public void dumpBundles() throws InvalidSyntaxException {
+ Bundle[] bundles = context.getBundles();
+ System.out.println(" === Bundles === ");
+ for (Bundle bundle : bundles) {
+ String sn = bundle.getSymbolicName();
+ System.out.println(sn);
+ }
+ System.out.println("====");
+ }
+
+ private void assertBundle(String sn) {
+ for (Bundle bundle : context.getBundles()) {
+ if (bundle.getSymbolicName().equals(sn)
+ && bundle.getState() == Bundle.ACTIVE) {
+ return;
+ }
+
+ }
+ Assert.fail("Cannot find the bundle " + sn);
+ }
+
+ private void assertValidity() {
+ try {
+ ServiceReference[] refs = context.getServiceReferences(Architecture.class.getName(), null);
+ Assert.assertNotNull(refs);
+ for (ServiceReference ref : refs) {
+ InstanceDescription id = ((Architecture) context.getService(ref)).getInstanceDescription();
+ int state = id.getState();
+ Assert.assertEquals("State of " + id.getName(), ComponentInstance.VALID, state);
+ }
+ } catch (InvalidSyntaxException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Waits for stability:
+ * <ul>
+ * <li>all bundles are activated
+ * <li>service count is stable
+ * </ul>
+ * If the stability can't be reached after a specified time,
+ * the method throws a {@link IllegalStateException}.
+ *
+ * @param context the bundle context
+ * @throws IllegalStateException when the stability can't be reach after a several attempts.
+ */
+ private void waitForStability(BundleContext context) throws IllegalStateException {
+ // Wait for bundle initialization.
+ boolean bundleStability = getBundleStability(context);
+ int count = 0;
+ while (!bundleStability && count < 500) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // Interrupted
+ }
+ count++;
+ bundleStability = getBundleStability(context);
+ }
+
+ if (count == 500) {
+ System.err.println("Bundle stability isn't reached after 500 tries");
+ throw new IllegalStateException("Cannot reach the bundle stability");
+ }
+
+ boolean serviceStability = false;
+ count = 0;
+ int count1 = 0;
+ int count2 = 0;
+ while (!serviceStability && count < 500) {
+ try {
+ ServiceReference[] refs = context.getServiceReferences((String) null, null);
+ count1 = refs.length;
+ Thread.sleep(1000);
+ refs = context.getServiceReferences((String) null, null);
+ count2 = refs.length;
+ serviceStability = count1 == count2;
+ } catch (Exception e) {
+ System.err.println(e);
+ serviceStability = false;
+ // Nothing to do, while recheck the condition
+ }
+ count++;
+ }
+
+ if (count == 500) {
+ System.err.println("Service stability isn't reached after 500 tries (" + count1 + " != " + count2);
+ throw new IllegalStateException("Cannot reach the service stability");
+ }
+ }
+
+ /**
+ * Are bundle stables.
+ *
+ * @param bc the bundle context
+ * @return <code>true</code> if every bundles are activated.
+ */
+ private boolean getBundleStability(BundleContext bc) {
+ boolean stability = true;
+ Bundle[] bundles = bc.getBundles();
+ for (Bundle bundle : bundles) {
+ stability = stability && (bundle.getState() == Bundle.ACTIVE);
+ }
+ return stability;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator-it/pom.xml b/ipojo/manipulator/manipulator-it/pom.xml
new file mode 100644
index 0000000..0311b9d
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/pom.xml
@@ -0,0 +1,407 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.manipulator.manipulator-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Manipulator ~ Integration Tests</name>
+ <packaging>pom</packaging>
+
+ <properties>
+ <!-- Tests are enabled only when the 'test' profile is activated -->
+ <skipTestExecution>true</skipTestExecution>
+
+ <exam.version>3.0.1</exam.version>
+ <url.version>1.5.1</url.version>
+
+ <felix.version>4.4.0</felix.version>
+ <equinox.version>3.9.0.v20130529-1710</equinox.version>
+ <knoperflerfish.version>6.0.2</knoperflerfish.version>
+ </properties>
+
+ <modules>
+ <module>ipojo-manipulator-manipulation-test</module>
+ <module>ipojo-manipulator-creation-test</module>
+ <module>ipojo-manipulator-manipulation-metadata-test</module>
+ <module>online-manipulator-it</module>
+ </modules>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ <exclude>src/it/**/target/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.15</version>
+ <configuration>
+ <skipTests>${skipTestExecution}</skipTests>
+ <systemPropertyVariables>
+ <!-- TIME_FACTOR can be set from the command line with -DTIME_FACTOR=9-->
+ <TIME_FACTOR>${TIME_FACTOR}</TIME_FACTOR>
+ <!-- Defined by the profiles -->
+ <pax.exam.framework>${pax.exam.framework}</pax.exam.framework>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+
+ <!-- The tiny bundle extension must be before the manipulator version
+ to use the right version of the manipulator -->
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Define the tested version -->
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <!-- To update before the release -->
+
+ <!--
+ if you are using a release version, be aware that this may introduce test failures as you should
+ update this version to the same version as the manipulator
+ -->
+ <version>1.12.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator.online</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- End of tested version -->
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <version>1.6.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.1</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.log</artifactId>
+ <version>1.0.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.easytesting</groupId>
+ <artifactId>fest-assert</artifactId>
+ <version>1.4</version>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>default</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <properties>
+ <pax.exam.framework>none</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>${knoperflerfish.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <!-- must be after KF -->
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>${equinox.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <!-- must be after equinox -->
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>${felix.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>test</id>
+ <properties>
+ <skipTestExecution>false</skipTestExecution>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/manipulator/manipulator-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/manipulator-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/manipulator/manipulator-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/manipulator/manipulator/changelog.txt b/ipojo/manipulator/manipulator/changelog.txt
new file mode 100644
index 0000000..a78c45c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/changelog.txt
@@ -0,0 +1,249 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3461] - Re-manipulation with annotated component produces corrupted MANIFEST
+ * [FELIX-3466] - Pojoization.directoryManipulation() does not take MANIFEST file location into account.
+ * [FELIX-3508] - IPojo Manipulator left out 'array of enums' in generated metadata
+ * [FELIX-3539] - iPOJO Manipulator failed on classes containing expanded frames
+ * [FELIX-3573] - IPojo bytecode manipulation generates a duplicate local variable
+ * [FELIX-3574] - IPojo bytecode manipulation looses method argument names
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+
+Changes from the 1.8.2 to 1.8.4
+-------------------------------
+
+** Bug
+ * [FELIX-3297] - iPOJO Manipulator throws ClassNotFoundException
+ * [FELIX-3359] - Turn around to avoid to use the split verifier on Java 7
+ * [FELIX-3389] - Bnd iPOJO Plugin ignores annotated components
+ * [FELIX-3391] - Unexpected warning when using bnd-ipojo-plugin
+
+** Improvement
+ * [FELIX-3384] - Ensure maven-ipojo-plugin is thread-safe for parallel maven builds
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+
+** Bug
+ * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files
+ * [FELIX-3012] - "Duplicate name&signature" problem
+ * [FELIX-3098] - iPOJO new manipulator crashes when using a custom reporter
+ * [FELIX-3145] - VerifyError on Java 7
+ * [FELIX-3249] - iPOJO Bnd Plugin do not write all the metadatas in the manifest
+
+** Improvement
+ * [FELIX-3017] - The manipulator should return the original class if it's already manipulated
+ * [FELIX-3078] - Introduce resource abstraction in the iPOJO manipulator
+ * [FELIX-3079] - Adapt the Ant task and the maven plugin to use the new manipulator capabilities
+ * [FELIX-3080] - Implement a BND plugin for iPOJO
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+ * [FELIX-3204] - @Temporal should handle instantiation-time properties
+ * [FELIX-3244] - Manipulator : DefaultManifestBuilder should be more extensible
+
+Changes from the 1.6.4 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2779] - iPOJO manipulator badly supports custom annotation attributes of type Class
+ * [FELIX-2664] - Native methods should not be manipulated
+
+** Improvement
+ * [FELIX-1424] - Constructor Injection
+ * [FELIX-1428] - Constructor injection of Configuration properties
+ * [FELIX-2620] - Change iPojo annotation parameters to follow java naming conventions
+ * [FELIX-2621] - Rename annotations to remove collisions
+ * [FELIX-2622] - Support static service properties that are not mirrored into fields
+ * [FELIX-2630] - Rename @Component attributes to follow the java naming conventions
+ * [FELIX-2732] - [iPOJO] Service modified callback should define a default method name
+ * [FELIX-2742] - Constructor injection of service dependencies
+ * [FELIX-2743] - Modify Pojoization to be more easily customizable
+ * [FELIX-2755] - Allow the manipulator and the different front end to use several metadata files
+
+Changes from the 1.6.2 to 1.6.4
+-------------------------------
+** Bug
+ * [FELIX-2430] - IPOJO manipulation (ant task) results in invalid classes throwing java.lang.VerifyError at runtime in InstanceManager
+
+** Improvement
+ * [FELIX-2420] - Enum support for @Property annotation
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+ * [FELIX-2485] - Improve the performance of the manipulator on large files
+ * [FELIX-2542] - Annotations on methods parameters are not moved on public methods after manipulation
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Improvement
+ * [FELIX-2296] - Access to ServiceReference in iPOJO service.
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1646] - Add @Handler annotation to declare handlers without metadata.xml
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+** Wish
+ * [FELIX-1940] - Add @Instance annotation to declare instances without metadata.xml
+
+
+Changes from the 1.4.0 to 1.4.2
+-------------------------------
+** Bug
+ * [FELIX-1411] - Issue on windows to find components inside bundle
+ * [FELIX-1518] - iPOJO manipulator is really slow even when annotation are ignored
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1302] - Manipulator never ignore annotations
+ * [FELIX-1319] - Issue in the metadata overiding analysis in iPOJO annotations
+
+** Improvement
+ * Update parent pom
+ * [FELIX-943] - Allow iPOJO manipulator to manipulate directories
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-788] - Failed to create object that extends super class with BundleContext argument
+
+** Improvement
+ * [FELIX-813] - Resolve XML-Schemas locally rather than from Internet
+ * [FELIX-830] - Simplify the "id/parent" resolution to compute the metadata hierarchy during annotation processing
+ * [FELIX-846] - Enhance the iPojo maven plugin to take metadata from pom.
+ * [FELIX-876] - Specification auto import is not supported for simple component types
+
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Bug
+ * [FELIX-649] - "Expecting to find object/array on stack" Error when asking for instance of an iPOJO component
+ * [FELIX-697] - Generation of a duplicated field when using generics
+ * [FELIX-739] - iPOJO and annotations support when manipulating
+ * [FELIX-751] - Wrong access for setter methods
+
+** Improvement
+ * [FELIX-655] - Add a 'from' attribute in the service dependencies
+ * [FELIX-678] - Improve missing fields detection during the packaging process
+ * [FELIX-687] - Support inner and nested classes
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/manipulator/manipulator/pom.xml b/ipojo/manipulator/manipulator/pom.xml
new file mode 100644
index 0000000..e3ffa6b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/pom.xml
@@ -0,0 +1,166 @@
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Manipulator</name>
+
+ <description>
+ iPOJO bytecode manipulator. This manipulator is used to instrument java classes in order to be managed by iPOJO.
+ </description>
+
+ <properties>
+ <ipojo.import.packages>[1.12.1,2.0.0)</ipojo.import.packages>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>5.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easytesting</groupId>
+ <artifactId>fest-assert</artifactId>
+ <version>1.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <!-- used in some tests -->
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.9</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>iPOJO Manipulator</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Manipulator</Bundle-Description>
+ <Export-Package>org.apache.felix.ipojo.manipulator.*
+ </Export-Package>
+ <Private-Package>org.apache.felix.ipojo.manipulation,
+ org.apache.felix.ipojo.xml.parser, org.objectweb.asm,
+ org.objectweb.asm.commons, org.objectweb.asm.tree
+ </Private-Package>
+ </instructions>
+ <obrRepository>NONE</obrRepository>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
+ </exclude>
+ <exclude>src/test/resources/MANIFEST.MF</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..caa7b23
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/LICENSE b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..9a2eac1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Manipulator:
+
+The Apache Felix iPOJO Manipulator includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..016e60d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
new file mode 100644
index 0000000..a83f0f7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -0,0 +1,846 @@
+/*
+ * 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.manipulation;
+
+import org.objectweb.asm.*;
+
+import java.util.*;
+
+/**
+ * Checks that a POJO is already manipulated or not.
+ * Moreover it allows to get manipulation data about this class.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ClassChecker extends ClassVisitor implements Opcodes {
+
+ /**
+ * True if the class is already manipulated.
+ */
+ private boolean m_isAlreadyManipulated = false;
+
+ /**
+ * Interfaces implemented by the component.
+ */
+ private List<String> m_itfs = new ArrayList<String>();
+
+ /**
+ * Field map [field name, type] discovered in the component class.
+ */
+ private Map<String, String> m_fields = new TreeMap<String, String>();
+
+ /**
+ * Method List of method descriptor discovered in the component class.
+ */
+ private List<MethodDescriptor> m_methods = new ArrayList<MethodDescriptor>();
+
+ /**
+ * Super class if not java.lang.Object.
+ */
+ private String m_superClass;
+
+ /**
+ * Class name.
+ */
+ private String m_className;
+
+ /**
+ * List of visited inner class owned by the implementation class.
+ */
+ private Map<String, List<MethodDescriptor>> m_inners = new LinkedHashMap<String, List<MethodDescriptor>>();
+
+ /**
+ * Class Version.
+ * Used to determine the frame format.
+ */
+ private int m_classVersion;
+
+ public ClassChecker() {
+ super(Opcodes.ASM5);
+ }
+
+ /**
+ * Check if the _cm field already exists.
+ * Update the field list.
+ *
+ * @param access : access of the field
+ * @param name : name of the field
+ * @param desc : description of the field
+ * @param signature : signature of the field
+ * @param value : value of the field (for static field only)
+ * @return the field visitor
+ * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public FieldVisitor visitField(int access, String name, String desc,
+ String signature, Object value) {
+ if (name.equals(ClassManipulator.IM_FIELD)
+ && desc.equals("Lorg/apache/felix/ipojo/InstanceManager;")) {
+ m_isAlreadyManipulated = true;
+ } else if (name.startsWith("class$")) { // Does not add class$* field generated by 'x.class'
+ return null;
+ } else if ((access & ACC_STATIC) == ACC_STATIC) {
+ return null;
+ }
+
+ if (isManipulatedField(name)) {
+ return null;
+ }
+
+ Type type = Type.getType(desc);
+ if (type.getSort() == Type.ARRAY) {
+ if (type.getInternalName().startsWith("L")) {
+ String internalType = type.getInternalName().substring(1);
+ String nameType = internalType.replace('/', '.');
+ m_fields.put(name, nameType + "[]");
+ } else {
+ String nameType = type.getClassName().substring(0,
+ type.getClassName().length() - 2);
+ m_fields.put(name, nameType + "[]");
+ }
+ } else {
+ m_fields.put(name, type.getClassName());
+ }
+
+ return null;
+ }
+
+ private boolean isManipulatedField(String name) {
+ return ((ClassManipulator.IM_FIELD.equals(name))
+ || (name.startsWith(ClassManipulator.FIELD_FLAG_PREFIX))
+ || (name.startsWith(ClassManipulator.METHOD_FLAG_PREFIX)));
+ }
+
+ /**
+ * Add the inner class to the list of inner class to manipulate.
+ * The method checks that the inner class is really owned by the implementation class.
+ *
+ * @param name inner class qualified name
+ * @param outerName outer class name (may be null for anonymous class)
+ * @param innerName inner class simple (i.e. short) name
+ * @param access inner class visibility
+ * @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)
+ */
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ if (m_className.equals(outerName) || outerName == null) { // Anonymous classes does not have an outer class.
+ // Do not include inner static class
+ if (!((access & ACC_STATIC) == ACC_STATIC)) {
+ m_inners.put(name, new ArrayList<MethodDescriptor>());
+ }
+ }
+ }
+
+
+ /**
+ * Check if the class was already manipulated.
+ *
+ * @return true if the class is already manipulated.
+ */
+ public boolean isAlreadyManipulated() {
+ return m_isAlreadyManipulated;
+ }
+
+ /**
+ * Gets the extracted class version
+ *
+ * @return the class version.
+ */
+ public int getClassVersion() {
+ return m_classVersion;
+ }
+
+ /**
+ * Visit the class.
+ * Update the implemented interface list.
+ *
+ * @param version : version of the class
+ * @param access : access of the class
+ * @param name : name of the class
+ * @param signature : signature of the class
+ * @param superName : super class of the class
+ * @param interfaces : implemented interfaces.
+ * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+
+ m_classVersion = version;
+
+ if (!superName.equals("java/lang/Object")) {
+ m_superClass = superName.replace('/', '.');
+ }
+
+ for (String anInterface : interfaces) {
+ if (!anInterface.equals("org/apache/felix/ipojo/Pojo")) {
+ m_itfs.add(anInterface.replace('/', '.'));
+ }
+ }
+
+ m_className = name;
+ }
+
+ /**
+ * Visit a method.
+ * Update the method list (except if it init or clinit.
+ *
+ * @param access - the method's access flags (see Opcodes). This parameter also indicates if the method is synthetic and/or deprecated.
+ * @param name - the method's name.
+ * @param desc - the method's descriptor (see Type).
+ * @param signature - the method's signature. May be null if the method parameters, return type and exceptions do not use generic types.
+ * @param exceptions - the internal names of the method's exception classes (see getInternalName). May be null.
+ * @return nothing.
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ if (!name.equals("<clinit>")) {
+
+ if (name.equals("<init>")) {
+ if (!isGeneratedConstructor(name, desc)) {
+ final MethodDescriptor md = new MethodDescriptor("$init", desc, (access & ACC_STATIC) == ACC_STATIC);
+ m_methods.add(md);
+ return new MethodInfoCollector(md);
+ }
+ } else {
+ // no constructors.
+ if (!isGeneratedMethod(name, desc)) {
+ final MethodDescriptor md = new MethodDescriptor(name, desc, (access & ACC_STATIC) == ACC_STATIC);
+ m_methods.add(md);
+ return new MethodInfoCollector(md);
+ }
+ }
+
+ }
+
+ if (name.equals("<clinit>")) {
+ return new InnerClassAssignedToStaticFieldDetector();
+ }
+
+ return null;
+ }
+
+ public static boolean isGeneratedConstructor(String name, String desc) {
+ return ("<init>".equals(name) && isFirstArgumentInstanceManager(desc));
+ }
+
+ public static boolean isFirstArgumentInstanceManager(String desc) {
+ Type[] types = Type.getArgumentTypes(desc);
+ return types != null && (types.length >= 1)
+ && Type.getType("Lorg/apache/felix/ipojo/InstanceManager;").equals(types[0]);
+ }
+
+ public static boolean isGeneratedMethod(String name, String desc) {
+ return isGetterMethod(name, desc)
+ || isSetterMethod(name, desc)
+ || isSetInstanceManagerMethod(name)
+ || isGetComponentInstanceMethod(name, desc)
+ || isManipulatedMethod(name);
+ }
+
+ private static boolean isGetterMethod(String name, String desc) {
+ // TYPE __getXXX()
+ Type[] arguments = Type.getArgumentTypes(desc);
+ return (name.startsWith("__get")
+ && (arguments.length == 0)
+ && !Type.VOID_TYPE.equals(Type.getReturnType(desc)));
+ }
+
+ private static boolean isSetterMethod(String name, String desc) {
+ // void __setXXX(TYPE)
+ Type[] arguments = Type.getArgumentTypes(desc);
+ return (name.startsWith("__set")
+ && (arguments.length == 1)
+ && Type.VOID_TYPE.equals(Type.getReturnType(desc)));
+ }
+
+ private static boolean isSetInstanceManagerMethod(String name) {
+ return name.startsWith("_setInstanceManager");
+ }
+
+ private static boolean isGetComponentInstanceMethod(String name, String desc) {
+ return (name.startsWith("getComponentInstance")
+ && Type.getType("Lorg/apache/felix/ipojo/ComponentInstance;").equals(Type.getReturnType(desc)));
+ }
+
+ private static boolean isManipulatedMethod(String name) {
+ return (name.startsWith(ClassManipulator.PREFIX));
+ }
+
+ /**
+ * Get collected interfaces.
+ *
+ * @return the interfaces implemented by the component class.
+ */
+ public List<String> getInterfaces() {
+ return m_itfs;
+ }
+
+ /**
+ * Get collected fields.
+ *
+ * @return the field map [field_name, type].
+ */
+ public Map<String, String> getFields() {
+ return m_fields;
+ }
+
+ /**
+ * Get collected methods.
+ *
+ * @return the method list of [method, signature].
+ */
+ public List<MethodDescriptor> getMethods() {
+ return m_methods;
+ }
+
+ public String getSuperClass() {
+ return m_superClass;
+ }
+
+ public Collection<String> getInnerClasses() {
+ return m_inners.keySet();
+ }
+
+ public Map<String, List<MethodDescriptor>> getInnerClassesAndMethods() {
+ return m_inners;
+ }
+
+ public String getClassName() {
+ return m_className;
+ }
+
+ /**
+ * This class collects annotations in a method.
+ * This class creates an {@link AnnotationDescriptor}
+ * if an annotation is found during the visit.
+ * It also collects local variables definition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ private final class MethodInfoCollector extends MethodVisitor {
+ /**
+ * The method descriptor of the visited method.
+ */
+ private MethodDescriptor m_method;
+
+ /**
+ * Creates an annotation collector.
+ *
+ * @param md the method descriptor of the visited method.
+ */
+ private MethodInfoCollector(MethodDescriptor md) {
+ super(Opcodes.ASM5);
+ m_method = md;
+ }
+
+ /**
+ * Visits an annotation.
+ * This class checks the visibility. If the annotation is visible,
+ * creates the {@link AnnotationDescriptor} corresponding to this annotation
+ * to visit this annotation. This {@link AnnotationDescriptor} is added to
+ * the {@link MethodDescriptor} of the visited method.
+ *
+ * @param name the name of the annotation
+ * @param visible is the annotation visible at runtime
+ * @return the {@link AnnotationDescriptor} to visit this annotation or
+ * <code>null</code> if the annotation is not visible.
+ * @see org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ if (visible) {
+ AnnotationDescriptor ann = new AnnotationDescriptor(name, true);
+ m_method.addAnnotation(ann);
+ return ann;
+ }
+ return null;
+ }
+
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ m_method.addLocalVariable(name, desc, signature, index);
+ }
+
+ public void visitEnd() {
+ m_method.end();
+ }
+
+ public AnnotationVisitor visitParameterAnnotation(int id,
+ String name, boolean visible) {
+ if (visible) {
+ AnnotationDescriptor ann = new AnnotationDescriptor(name, true);
+ m_method.addParameterAnnotation(id, ann);
+ return ann;
+ }
+
+ /*
+ * It is harmless to keep injected parameter annotations on original constructor
+ * for correct property resolution in case of re-manipulation
+ */
+ if (m_method.getName().equals("$init")) {
+ AnnotationDescriptor ann = new AnnotationDescriptor(name, false);
+ m_method.addParameterAnnotation(id, ann);
+ return ann;
+ }
+
+ return null;
+ }
+
+
+ }
+
+ /**
+ * Describes a method or constructor annotation.
+ * This allows creating a copy of the annotations found in the original class
+ * to move them on inserted method. This class implements an
+ * {@link AnnotationVisitor} in order to create the copy.
+ * This class contains a <code>visit</code> method re-injecting the
+ * annotation in the generated method.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public class AnnotationDescriptor extends AnnotationVisitor {
+ /**
+ * The name of the annotation.
+ */
+ private String m_name;
+ /**
+ * Is the annotation visible at runtime?
+ */
+ private boolean m_visible;
+ /**
+ * The description of the annotation.
+ * This attribute is set only for nested annotations.
+ */
+ private String m_desc;
+ /**
+ * The list of 'simple' attributes.
+ */
+ private List<SimpleAttribute> m_simples = new ArrayList<SimpleAttribute>(0);
+ /**
+ * The list of attribute containing an
+ * enumeration value.
+ */
+ private List<EnumAttribute> m_enums = new ArrayList<EnumAttribute>(0);
+ /**
+ * The list of attribute which are
+ * annotations.
+ */
+ private List<AnnotationDescriptor> m_nested = new ArrayList<AnnotationDescriptor>(0);
+ /**
+ * The list of attribute which are
+ * arrays.
+ */
+ private List<ArrayAttribute> m_arrays = new ArrayList<ArrayAttribute>(0);
+
+
+ /**
+ * Creates an annotation descriptor.
+ * This constructor is used for 'root' annotations.
+ *
+ * @param name the name of the annotation
+ * @param visible the visibility of the annotation at runtime
+ */
+ public AnnotationDescriptor(String name, boolean visible) {
+ super(Opcodes.ASM5);
+ m_name = name;
+ m_visible = visible;
+ }
+
+ /**
+ * Creates an annotation descriptor.
+ * This constructor is used for nested annotations.
+ *
+ * @param name the name of the annotation
+ * @param desc the descriptor of the annotation
+ */
+ public AnnotationDescriptor(String name, String desc) {
+ super(Opcodes.ASM5);
+ m_name = name;
+ m_visible = true;
+ m_desc = desc;
+ }
+
+
+ /**
+ * Visits a simple attribute.
+ *
+ * @param arg0 the attribute name
+ * @param arg1 the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ m_simples.add(new SimpleAttribute(arg0, arg1));
+ }
+
+
+ /**
+ * Visits a nested annotation.
+ *
+ * @param arg0 the attribute name
+ * @param arg1 the annotation descriptor
+ * @return the annotation visitor parsing the nested annotation
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ AnnotationDescriptor ad = new AnnotationDescriptor(arg0, arg1);
+ m_nested.add(ad);
+ return ad;
+ }
+
+
+ /**
+ * Visits an array attribute.
+ *
+ * @param arg0 the name of the attribute
+ * @return the annotation visitor parsing the content of the array,
+ * uses a specific {@link ArrayAttribute} to parse this array
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ ArrayAttribute aa = new ArrayAttribute(arg0);
+ m_arrays.add(aa);
+ return aa;
+ }
+
+
+ /**
+ * End of the visit.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ }
+
+
+ /**
+ * Visits an enumeration attribute.
+ *
+ * @param arg0 the attribute name
+ * @param arg1 the enumeration descriptor
+ * @param arg2 the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ m_enums.add(new EnumAttribute(arg0, arg1, arg2));
+ }
+
+ /**
+ * Methods allowing to recreate the visited (stored) annotation
+ * into the destination method.
+ * This method recreate the annotations itself and any other
+ * attributes.
+ *
+ * @param mv the method visitor visiting the destination method.
+ */
+ public void visitAnnotation(MethodVisitor mv) {
+ AnnotationVisitor av = mv.visitAnnotation(m_name, m_visible);
+ for (SimpleAttribute simple : m_simples) {
+ simple.visit(av);
+ }
+ for (EnumAttribute en : m_enums) {
+ en.visit(av);
+ }
+ for (AnnotationDescriptor nested : m_nested) {
+ nested.visit(av);
+ }
+ for (ArrayAttribute array : m_arrays) {
+ array.visit(av);
+ }
+ av.visitEnd();
+ }
+
+ /**
+ * Methods allowing to recreate the visited (stored) parameter annotations
+ * into the destination method.
+ * This method recreate the annotations itself and any other
+ * attributes.
+ *
+ * @param id the paramter id
+ * @param mv the method visitor visiting the destination method.
+ */
+ public void visitParameterAnnotation(int id, MethodVisitor mv) {
+ AnnotationVisitor av = mv.visitParameterAnnotation(id, m_name, m_visible);
+ for (SimpleAttribute simple : m_simples) {
+ simple.visit(av);
+ }
+ for (EnumAttribute en : m_enums) {
+ en.visit(av);
+ }
+ for (AnnotationDescriptor nested : m_nested) {
+ nested.visit(av);
+ }
+ for (ArrayAttribute array : m_arrays) {
+ array.visit(av);
+ }
+ av.visitEnd();
+ }
+
+ /**
+ * Method allowing to recreate the visited (stored) annotation
+ * into the destination annotation. This method is used only
+ * for nested annotation.
+ *
+ * @param mv the annotation visitor to populate with the stored
+ * annotation
+ */
+ public void visit(AnnotationVisitor mv) {
+ AnnotationVisitor av = mv.visitAnnotation(m_name, m_desc);
+ for (SimpleAttribute simple : m_simples) {
+ simple.visit(av);
+ }
+ for (EnumAttribute enu : m_enums) {
+ enu.visit(av);
+ }
+ for (AnnotationDescriptor nested : m_nested) {
+ nested.visit(av);
+ }
+ for (ArrayAttribute array : m_arrays) {
+ array.visit(av);
+ }
+ av.visitEnd();
+ }
+
+
+ }
+
+ /**
+ * Describes an array attribute.
+ * This class is able to visit an annotation array attribute, and to
+ * recreate this array on another annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public class ArrayAttribute extends AnnotationVisitor {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The content of the parsed array.
+ */
+ private List<Object> m_content = new ArrayList<Object>();
+
+ /**
+ * Creates an array attribute.
+ *
+ * @param name the name of the attribute.
+ */
+ public ArrayAttribute(String name) {
+ super(Opcodes.ASM5);
+ m_name = name;
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * simple values.
+ *
+ * @param arg0 <code>null</code>
+ * @param arg1 the value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ m_content.add(arg1);
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * nested annotations (annotations contained in the array).
+ *
+ * @param arg0 <code>null</code>
+ * @param arg1 the annotation descriptor
+ * @return an {@link AnnotationDescriptor} which creates a copy of
+ * the contained annotation.
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ AnnotationDescriptor ad = new AnnotationDescriptor(null, arg1);
+ m_content.add(ad);
+ return ad;
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * nested arrays (arrays contained in the array).
+ *
+ * @param arg0 <code>null</code>
+ * @return an {@link AnnotationVisitor} which creates a copy of
+ * the contained array.
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ ArrayAttribute aa = new ArrayAttribute(null);
+ m_content.add(aa);
+ return aa;
+ }
+
+ /**
+ * End of the array attribute visit.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ }
+
+ /**
+ * Visits the content of the array. This method is called for
+ * enumeration values.
+ *
+ * @param arg0 <code>null</code>
+ * @param arg1 the enumeration descriptor
+ * @param arg2 the value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)
+ */
+ public void visitEnum(String arg0, String arg1, String arg2) {
+ EnumAttribute ea = new EnumAttribute(null, arg1, arg2);
+ m_content.add(ea);
+ }
+
+ /**
+ * Recreates the visited array attribute. This method
+ * handle the generation of the object embedded in the
+ * array.
+ *
+ * @param av the annotation visitor on which the array attribute
+ * needs to be injected.
+ */
+ public void visit(AnnotationVisitor av) {
+ AnnotationVisitor content = av.visitArray(m_name);
+ for (Object component : m_content) {
+ if (component instanceof AnnotationDescriptor) {
+ ((AnnotationDescriptor) component).visit(content);
+ } else if (component instanceof EnumAttribute) {
+ ((EnumAttribute) component).visit(content);
+ } else if (component instanceof ArrayAttribute) {
+ ((ArrayAttribute) component).visit(content);
+ } else { // Simple
+ content.visit(null, component);
+ }
+ }
+ content.visitEnd();
+ }
+
+ }
+
+ /**
+ * Describes a simple attribute.
+ * This class is able to visit an annotation simple attribute, and to
+ * recreate this attribute on another annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public static final class SimpleAttribute {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The value of the attribute.
+ */
+ private Object m_value;
+
+ /**
+ * Creates a simple attribute.
+ *
+ * @param name the name of the attribute
+ * @param object the value of the attribute
+ */
+ private SimpleAttribute(String name, Object object) {
+ m_name = name;
+ m_value = object;
+ }
+
+ /**
+ * Recreates the attribute on the given annotation.
+ *
+ * @param visitor the visitor on which the attribute needs
+ * to be injected.
+ */
+ public void visit(AnnotationVisitor visitor) {
+ visitor.visit(m_name, m_value);
+ }
+ }
+
+ /**
+ * Describes an attribute. The value of this attribute is an enumerated
+ * value.
+ * This class is able to visit an annotation enumeration attribute, and to
+ * recreate this attribute on another annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ public static final class EnumAttribute {
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+ /**
+ * The descriptor of the enumeration.
+ */
+ private String m_desc;
+ /**
+ * The value of the attribute.
+ */
+ private String m_value;
+
+ /**
+ * Creates a enumeration attribute.
+ *
+ * @param name the name of the attribute.
+ * @param desc the descriptor of the {@link Enum}
+ * @param value the enumerated value
+ */
+ private EnumAttribute(String name, String desc, String value) {
+ m_name = name;
+ m_value = value;
+ m_desc = desc;
+ }
+
+ /**
+ * Recreates the attribute on the given annotation.
+ *
+ * @param visitor the visitor on which the attribute needs
+ * to be injected.
+ */
+ public void visit(AnnotationVisitor visitor) {
+ visitor.visitEnum(m_name, m_desc, m_value);
+ }
+
+ }
+
+
+ /**
+ * Class required to detect inner classes assigned to static field and thus must not be manipulated (FELIX-4347).
+ * If an inner class is assigned to a static field, it must not be manipulated.
+ * <p/>
+ * However notice that this is only useful when AspectJ is used, because aspectJ is changing the 'staticity' of
+ * the inner class.
+ */
+ private class InnerClassAssignedToStaticFieldDetector extends MethodVisitor {
+
+ public InnerClassAssignedToStaticFieldDetector() {
+ super(Opcodes.ASM5);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ if (opcode == NEW && m_inners.containsKey(type)) {
+ m_inners.remove(type);
+ }
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java
new file mode 100644
index 0000000..dc03688
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.manipulation;
+
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * An extension of {@link org.objectweb.asm.ClassWriter} that uses a specific classloader to load classes.
+ */
+public class ClassLoaderAwareClassWriter extends ClassWriter {
+
+ private static final String OBJECT_INTERNAL_NAME = "java/lang/Object";
+ private final String className;
+ private final String superClass;
+ private final ClassLoader classLoader;
+
+ public ClassLoaderAwareClassWriter(int flags, String className, String superClass, ClassLoader loader) {
+ super(flags);
+ this.className = className;
+ this.superClass = superClass;
+ this.classLoader = loader;
+ }
+
+ /**
+ * Implements the common super class lookup to be a bit more permissive. First we check is type1 == type2,
+ * because in this case, the lookup is done. Then, if one of the class is Object,
+ * returns object. If both checks failed, it returns Object.
+ *
+ * @param type1 the first class
+ * @param type2 the second class
+ * @return the common super class
+ */
+ @Override
+ protected final String getCommonSuperClass(String type1, String type2) {
+ //If the two are equal then return either
+ if (type1.equals(type2)) {
+ return type1;
+ }
+
+ //If either is Object, then Object must be the answer
+ if (type1.equals(OBJECT_INTERNAL_NAME) || type2.equals(OBJECT_INTERNAL_NAME)) {
+ return OBJECT_INTERNAL_NAME;
+ }
+
+ // If either of these class names are the current class then we can short
+ // circuit to the superclass (which we already know)
+ if (type1.equals(className.replace(".", "/")) && superClass != null) {
+ return getCommonSuperClass(superClass.replace(".", "/"), type2);
+ } else if (type2.equals(className.replace(".", "/")) && superClass != null)
+ return getCommonSuperClass(type1, superClass.replace(".", "/"));
+
+ Class<?> c, d;
+ try {
+ c = classLoader.loadClass(type1.replace('/', '.'));
+ d = classLoader.loadClass(type2.replace('/', '.'));
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ }
+ if (c.isAssignableFrom(d)) {
+ return type1;
+ }
+ if (d.isAssignableFrom(c)) {
+ return type2;
+ }
+ if (c.isInterface() || d.isInterface()) {
+ return "java/lang/Object";
+ } else {
+ do {
+ c = c.getSuperclass();
+ } while (!c.isAssignableFrom(d));
+ return c.getName().replace('.', '/');
+ }
+ }
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassManipulator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassManipulator.java
new file mode 100644
index 0000000..de5fd3f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassManipulator.java
@@ -0,0 +1,1172 @@
+/*
+ * 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.manipulation;
+
+import java.util.*;
+
+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.tree.LocalVariableNode;
+
+/**
+ * iPOJO Class Adapter.
+ * This class adapt the visited class to link the class with the container.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ClassManipulator extends ClassVisitor implements Opcodes {
+
+ /**
+ * Instance Manager Field.
+ */
+ public static final String IM_FIELD = "__IM";
+
+ /**
+ * All POJO method will be renamed by using this prefix.
+ */
+ public static final String PREFIX = "__M_";
+
+ /**
+ * POJO class.
+ */
+ private static final String POJO = "org/apache/felix/ipojo/Pojo";
+
+ /**
+ * Filed flag prefix.
+ */
+ public static final String FIELD_FLAG_PREFIX = "__F";
+
+ /**
+ * Method flag prefix.
+ */
+ public static final String METHOD_FLAG_PREFIX = "__M";
+
+ /**
+ * onEntry method name.
+ */
+ public static final String ENTRY = "onEntry";
+
+ /**
+ * onExit method name.
+ */
+ public static final String EXIT = "onExit";
+
+ /**
+ * on Error method name.
+ */
+ public static final String ERROR = "onError";
+
+ /**
+ * onGet method name.
+ */
+ private static final String GET = "onGet";
+
+ /**
+ * onSet method name.
+ */
+ private static final String SET = "onSet";
+
+ /**
+ * The manipulator. It has already collected all the metadata about the class.
+ */
+ private final Manipulator m_manipulator;
+
+ /**
+ * Name of the current manipulated class.
+ */
+ private String m_owner;
+
+ /**
+ * Set of fields detected in the class.
+ * (this set is given by the previous analysis)
+ */
+ private Set<String> m_fields;
+
+ /**
+ * List of methods contained in the class.
+ * This set contains method id.
+ */
+ private List<String> m_methods = new ArrayList<String>();
+
+ /**
+ * List of fields injected as method flag in the class.
+ * This set contains field name generate from method id.
+ */
+ private List<String> m_methodFlags = new ArrayList<String>();
+
+ /**
+ * The list of methods visited during the previous analysis.
+ * This list allows getting annotations to move to generated
+ * method.
+ */
+ private List<MethodDescriptor> m_visitedMethods = new ArrayList<MethodDescriptor>();
+
+ /**
+ * Set to <code>true</code> when a suitable constructor
+ * is found. If not set to <code>true</code> at the end
+ * of the visit, the manipulator injects a constructor.
+ */
+ private boolean m_foundSuitableConstructor = false;
+
+ /**
+ * Name of the super class.
+ */
+ private String m_superclass;
+
+ /**
+ * Constructor.
+ * @param visitor : class visitor.
+ * @param manipulator : the manipulator having analyzed the class.
+ */
+ public ClassManipulator(ClassVisitor visitor, Manipulator manipulator) {
+ super(Opcodes.ASM5, visitor);
+ m_manipulator = manipulator;
+ m_fields = manipulator.getFields().keySet();
+ m_visitedMethods = manipulator.getMethods();
+ }
+
+ /**
+ * Visit method.
+ * This method store the current class name.
+ * Moreover the POJO interface is added to the list of implemented interface.
+ * Then the Instance manager field is added.
+ * @param version : version
+ * @param access : access flag
+ * @param name : class name
+ * @param signature : signature
+ * @param superName : parent class
+ * @param interfaces : implemented interface
+ * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.String[])
+ */
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ m_owner = name;
+ m_superclass = superName;
+ addPOJOInterface(version, access, name, signature, superName, interfaces);
+ addIMField();
+ addFlagsForInnerClassMethods();
+ }
+
+ /**
+ * A method is visited.
+ * This method does not manipulate clinit and class$ methods.
+ * In the case of a constructor, this method will generate a constructor with the instance manager
+ * and will adapt the current constructor to call this constructor.
+ * For standard method, this method will create method header, rename the current method and adapt it.
+ * @param access : access flag.
+ * @param name : name of the method
+ * @param desc : method descriptor
+ * @param signature : signature
+ * @param exceptions : declared exceptions.
+ * @return the MethodVisitor wich will visit the method code.
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.String[])
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ // Avoid manipulating special methods
+ if (name.equals("<clinit>") || name.equals("class$")) { return super.visitMethod(access, name, desc, signature, exceptions); }
+ // The constructor is manipulated separately
+ if (name.equals("<init>")) {
+ MethodDescriptor md = getMethodDescriptor("$init", desc);
+ // 1) change the constructor descriptor (add a component manager arg as first argument)
+ String newDesc = desc.substring(1);
+ newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;
+
+ Type[] args = Type.getArgumentTypes(desc);
+
+ // TODO HERE ! => All constructor matches, no distinction between the different constructors.
+ generateConstructor(access, desc, signature, exceptions, md.getAnnotations(),
+ md.getParameterAnnotations(), md.getLocals());
+
+ if (args.length == 0) {
+ m_foundSuitableConstructor = true;
+ } else if (args.length == 1 && args[0].getClassName().equals("org.osgi.framework.BundleContext")) {
+ m_foundSuitableConstructor = true;
+ }
+
+ // Insert the new constructor
+ MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "<init>", newDesc, signature, exceptions);
+ return new ConstructorCodeAdapter(mv, m_owner, m_fields, ACC_PRIVATE, name, newDesc, m_superclass);
+ }
+
+ if ((access & ACC_SYNTHETIC) == ACC_SYNTHETIC && name.startsWith("access$")) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ return new MethodCodeAdapter(mv, m_owner, access, name, desc, m_fields);
+ }
+
+ // Do nothing on static methods
+ if ((access & ACC_STATIC) == ACC_STATIC) { return super.visitMethod(access, name, desc, signature, exceptions); }
+
+ // Do nothing on native methods
+ if ((access & ACC_NATIVE) == ACC_NATIVE) { return super.visitMethod(access, name, desc, signature, exceptions); }
+
+ MethodDescriptor md = getMethodDescriptor(name, desc);
+ if (md == null) {
+ generateMethodHeader(access, name, desc, signature, exceptions, null, null, null);
+ } else {
+ generateMethodHeader(access, name, desc, signature, exceptions, md.getArgumentLocalVariables(),
+ md.getAnnotations(), md.getParameterAnnotations());
+ }
+
+ // TODO Also add the method flags for inner class methods.
+ String id = generateMethodFlag(name, desc);
+ if (! m_methodFlags.contains(id)) {
+ FieldVisitor flagField = cv.visitField(0, id, "Z", null, null);
+ flagField.visitEnd();
+ m_methodFlags.add(id);
+ }
+
+ MethodVisitor mv = super.visitMethod(ACC_PRIVATE, PREFIX + name, desc, signature, exceptions);
+ return new MethodCodeAdapter(mv, m_owner, ACC_PRIVATE, PREFIX + name, desc, m_fields);
+ }
+
+ /**
+ * Gets the method descriptor for the specified name and descriptor.
+ * The method descriptor is looked inside the
+ * {@link ClassManipulator#m_visitedMethods}
+ * @param name the name of the method
+ * @param desc the descriptor of the method
+ * @return the method descriptor or <code>null</code> if not found.
+ */
+ private MethodDescriptor getMethodDescriptor(String name, String desc) {
+ for (MethodDescriptor md : m_visitedMethods) {
+ if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {
+ return md;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Visit a Field.
+ * This field access is replaced by an invocation to the getter method or to the setter method.
+ * (except for static field).
+ * Inject the getter and the setter method for this field.
+ * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
+ * @param access : access modifier
+ * @param name : name of the field
+ * @param desc : description of the field
+ * @param signature : signature of the field
+ * @param value : value of the field
+ * @return FieldVisitor : null
+ */
+ public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
+ if ((access & ACC_STATIC) == 0) {
+ FieldVisitor flag = cv.visitField(Opcodes.ACC_PRIVATE, FIELD_FLAG_PREFIX + name, "Z", null, null);
+ flag.visitEnd();
+
+ Type type = Type.getType(desc);
+
+ if (type.getSort() == Type.ARRAY) {
+ String gDesc = "()" + desc;
+ createArrayGetter(name, gDesc);
+
+ // Generates setter method
+ String sDesc = "(" + desc + ")V";
+ createArraySetter(name, sDesc);
+
+ } else {
+ // Generate the getter method
+ String gDesc = "()" + desc;
+ createSimpleGetter(name, gDesc, type);
+
+ // Generates setter method
+ String sDesc = "(" + desc + ")V";
+ createSimpleSetter(name, sDesc, type);
+ }
+
+ }
+ return cv.visitField(access, name, desc, signature, value);
+ }
+
+ /**
+ * Modify the given constructor to be something like:
+ * <code>
+ * this(null, params...);
+ * return;
+ * </code>
+ * The actual constructor is modified to support the instance manager argument.
+ * @param access : access flag
+ * @param descriptor : the original constructor descriptor
+ * @param signature : method signature
+ * @param exceptions : declared exception
+ * @param annotations : the annotations to move to this constructor.
+ * @param locals : the local variables from the original constructors.
+ */
+ private void generateConstructor(int access, String descriptor, String signature, String[] exceptions,
+ List<AnnotationDescriptor> annotations, Map<Integer,
+ List<AnnotationDescriptor>> paramAnnotations, LinkedHashMap<Integer, LocalVariableNode> locals) {
+ GeneratorAdapter mv = new GeneratorAdapter(
+ cv.visitMethod(access, "<init>", descriptor, signature, exceptions),
+ access, "<init>", descriptor);
+ // Compute the new signature
+ String newDesc = descriptor.substring(1); // Remove the first (
+ newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;
+
+ mv.visitCode();
+ Label start = new Label();
+ mv.visitLabel(start);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitInsn(ACONST_NULL);
+ mv.loadArgs();
+ mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", newDesc, false);
+ mv.visitInsn(RETURN);
+ Label stop = new Label();
+ mv.visitLabel(stop);
+
+ // Move annotations
+ if (annotations != null) {
+ for (AnnotationDescriptor ad : annotations) {
+ ad.visitAnnotation(mv);
+ }
+ }
+
+ // Move parameter annotations if any
+ if (paramAnnotations != null && ! paramAnnotations.isEmpty()) {
+ for (Integer id : paramAnnotations.keySet()) {
+ List<AnnotationDescriptor> ads = paramAnnotations.get(id);
+ for (AnnotationDescriptor ad : ads) {
+ ad.visitParameterAnnotation(id, mv);
+ }
+ }
+ }
+
+ // Add local variables for the arguments.
+ for (Map.Entry<Integer, LocalVariableNode> local : locals.entrySet()) {
+ // Write the parameter name. Only write the local variable that are either `this` or parameters from the
+ // initial descriptor.
+ if (local.getValue().index <= Type.getArgumentTypes(descriptor).length) {
+ mv.visitLocalVariable(local.getValue().name, local.getValue().desc, local.getValue().signature, start,stop,
+ local.getValue().index);
+ }
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate the method header of a POJO method.
+ * This method header encapsulate the POJO method call to
+ * signal entry exit and error to the container.
+ * @param access : access flag.
+ * @param name : method name.
+ * @param desc : method descriptor.
+ * @param signature : method signature.
+ * @param exceptions : declared exceptions.
+ * @param localVariables : the local variable nodes.
+ * @param annotations : the annotations to move to this method.
+ * @param paramAnnotations : the parameter annotations to move to this method.
+ */
+ private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions,
+ List<LocalVariableNode> localVariables, List<AnnotationDescriptor> annotations,
+ Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {
+ GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc);
+ mv.visitCode();
+
+ // If we have variables, we wraps the code within labels. The `lifetime` of the variables are bound to those
+ // two variables.
+ boolean hasArgumentLabels = localVariables != null && !localVariables.isEmpty();
+ Label start = null;
+ if (hasArgumentLabels) {
+ start = new Label();
+ mv.visitLabel(start);
+ }
+
+ mv.visitCode();
+
+ Type returnType = Type.getReturnType(desc);
+
+ // Compute result and exception stack location
+ int result = -1;
+ int exception;
+
+ //int arguments = mv.newLocal(Type.getType((new Object[0]).getClass()));
+
+ if (returnType.getSort() != Type.VOID) {
+ // The method returns something
+ result = mv.newLocal(returnType);
+ exception = mv.newLocal(Type.getType(Throwable.class));
+ } else {
+ exception = mv.newLocal(Type.getType(Throwable.class));
+ }
+
+ Label l0 = new Label();
+ Label l1 = new Label();
+ Label l2 = new Label();
+
+ mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, generateMethodFlag(name, desc), "Z");
+ mv.visitJumpInsn(IFNE, l0);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.loadArgs();
+ mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc, false);
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+
+ // end of the non intercepted method invocation.
+
+ mv.visitLabel(l0);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(generateMethodId(name, desc));
+ mv.loadArgArray();
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ENTRY,
+ "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V", false);
+
+ mv.visitVarInsn(ALOAD, 0);
+
+ // Do not allow argument modification : just reload arguments.
+ mv.loadArgs();
+ mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc, false);
+
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ISTORE), result);
+ }
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(generateMethodId(name, desc));
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
+ mv.box(returnType);
+ } else {
+ mv.visitInsn(ACONST_NULL);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", EXIT,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ mv.visitLabel(l1);
+ Label l7 = new Label();
+ mv.visitJumpInsn(GOTO, l7);
+ mv.visitLabel(l2);
+
+ mv.visitVarInsn(ASTORE, exception);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(generateMethodId(name, desc));
+ mv.visitVarInsn(ALOAD, exception);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ERROR,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V", false);
+ mv.visitVarInsn(ALOAD, exception);
+ mv.visitInsn(ATHROW);
+
+ mv.visitLabel(l7);
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
+ }
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+
+ // If we had arguments, we mark the end of the lifetime.
+ Label end = null;
+ if (hasArgumentLabels) {
+ end = new Label();
+ mv.visitLabel(end);
+ }
+
+ // Move annotations
+ if (annotations != null) {
+ for (AnnotationDescriptor ad : annotations) {
+ ad.visitAnnotation(mv);
+ }
+ }
+
+ // Move parameter annotations
+ if (paramAnnotations != null && ! paramAnnotations.isEmpty()) {
+ for (Integer id : paramAnnotations.keySet()) {
+ List<AnnotationDescriptor> ads = paramAnnotations.get(id);
+ for (AnnotationDescriptor ad : ads) {
+ ad.visitParameterAnnotation(id, mv);
+ }
+ }
+ }
+
+ // Write the arguments name.
+ if (hasArgumentLabels) {
+ for (LocalVariableNode var : localVariables) {
+ mv.visitLocalVariable(var.name, var.desc, var.signature, start, end, var.index);
+ }
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate a method flag name.
+ * @param name : method name.
+ * @param desc : method descriptor.
+ * @return the method flag name
+ */
+ private String generateMethodFlag(String name, String desc) {
+ return METHOD_FLAG_PREFIX + generateMethodId(name, desc);
+ }
+
+ private String generateMethodFlagForMethodFromInnerClass(String name, String desc, String inner) {
+ return METHOD_FLAG_PREFIX + generateMethodIdForMethodFromInnerClass(name, desc, inner);
+ }
+
+ /**
+ * Generate the method id based on the given method name and method descriptor.
+ * The method Id is unique for this method and serves to create the flag field (so
+ * must follow field name Java restrictions).
+ * @param name : method name
+ * @param desc : method descriptor
+ * @return method ID
+ */
+ private String generateMethodId(String name, String desc) {
+ StringBuilder id = new StringBuilder(name);
+ Type[] args = Type.getArgumentTypes(desc);
+ for (Type type : args) {
+ String arg = type.getClassName();
+ if (arg.endsWith("[]")) {
+ // We have to replace all []
+ String acc = "";
+ while (arg.endsWith("[]")) {
+ arg = arg.substring(0, arg.length() - 2);
+ acc += "__";
+ }
+ id.append("$").append(arg.replace('.', '_')).append(acc);
+ } else {
+ id.append("$").append(arg.replace('.', '_'));
+ }
+ }
+ if (!m_methods.contains(id.toString())) {
+ m_methods.add(id.toString());
+ }
+ return id.toString();
+ }
+
+ private String generateMethodIdForMethodFromInnerClass(String name, String desc, String inner) {
+ StringBuilder id = new StringBuilder(inner);
+ id.append("___"); // Separator
+ id.append(name);
+
+ Type[] args = Type.getArgumentTypes(desc);
+ for (Type type : args) {
+ String arg = type.getClassName();
+ if (arg.endsWith("[]")) {
+ // We have to replace all []
+ String acc = "";
+ while (arg.endsWith("[]")) {
+ arg = arg.substring(0, arg.length() - 2);
+ acc += "__";
+ }
+ id.append("$").append(arg.replace('.', '_')).append(acc);
+ } else {
+ id.append("$").append(arg.replace('.', '_'));
+ }
+ }
+
+ if (!m_methods.contains(id.toString())) {
+ m_methods.add(id.toString());
+ }
+
+ return id.toString();
+ }
+
+ /**
+ * Add the instance manager field (__im).
+ */
+ private void addIMField() {
+ FieldVisitor fv = super.visitField(0, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;", null, null);
+ fv.visitEnd();
+ }
+
+ /**
+ * Add the boolean flag fields for methods from inner classes.
+ */
+ private void addFlagsForInnerClassMethods() {
+ for (Map.Entry<String, List<MethodDescriptor>> entry : m_manipulator.getInnerClassesAndMethods().entrySet()) {
+ for (MethodDescriptor descriptor : entry.getValue()) {
+ String id = generateMethodFlagForMethodFromInnerClass(
+ descriptor.getName(),
+ descriptor.getDescriptor(),
+ entry.getKey());
+ if (! m_methodFlags.contains(id)) {
+ FieldVisitor flagField = cv.visitField(0, id, "Z", null, null);
+ flagField.visitEnd();
+ m_methodFlags.add(id);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the POJO interface to the visited class.
+ * @param version : class version
+ * @param access : class access
+ * @param name : class name
+ * @param signature : class signature
+ * @param superName : super class
+ * @param interfaces : implemented interfaces.
+ */
+ private void addPOJOInterface(int version, int access, String name, String signature, String superName, String[] interfaces) {
+
+ // Add the POJO interface to the interface list
+ // Check that the POJO interface is not already in the list
+ boolean found = false;
+ for (String anInterface : interfaces) {
+ if (anInterface.equals(POJO)) {
+ found = true;
+ }
+ }
+ String[] itfs;
+ if (!found) {
+ itfs = new String[interfaces.length + 1];
+ System.arraycopy(interfaces, 0, itfs, 0, interfaces.length);
+ itfs[interfaces.length] = POJO;
+ } else {
+ itfs = interfaces;
+ }
+ cv.visit(version, access, name, signature, superName, itfs);
+ }
+
+ /**
+ * Visit end.
+ * Create helper methods.
+ * @see org.objectweb.asm.ClassVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // Create the component manager setter method
+ createSetInstanceManagerMethod();
+
+ // Add the getComponentInstance
+ createGetComponentInstanceMethod();
+
+ // Need to inject a constructor?
+ if (! m_foundSuitableConstructor) { // No adequate constructor, create one.
+ createSimpleConstructor();
+ }
+
+ m_methods.clear();
+ m_methodFlags.clear();
+
+ cv.visitEnd();
+ }
+
+ /**
+ * Creates a simple constructor with an instance manager
+ * in argument if no suitable constructor is found during
+ * the visit.
+ */
+ private void createSimpleConstructor() {
+ MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>",
+ "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);
+ mv.visitCode();
+
+ // Super call
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, m_superclass, "<init>", "()V", false);
+
+ // Call set instance manager
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_setInstanceManager",
+ "(Lorg/apache/felix/ipojo/InstanceManager;)V", false);
+
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the setter method for the __cm field.
+ */
+ private void createSetInstanceManagerMethod() {
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_setInstanceManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);
+ mv.visitCode();
+
+ // If the given instance manager is null, just returns.
+ mv.visitVarInsn(ALOAD, 1);
+ Label l1 = new Label();
+ mv.visitJumpInsn(IFNONNULL, l1);
+ mv.visitInsn(RETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredFields",
+ "()Ljava/util/Set;", false);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ Label endif = new Label();
+ mv.visitJumpInsn(IFNULL, endif);
+ for (String field : m_fields) {
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitLdcInsn(field);
+ mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z", true);
+ Label l3 = new Label();
+ mv.visitJumpInsn(IFEQ, l3);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitInsn(ICONST_1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, FIELD_FLAG_PREFIX + field, "Z");
+ mv.visitLabel(l3);
+ }
+ mv.visitLabel(endif);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredMethods",
+ "()Ljava/util/Set;", false);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ Label endif2 = new Label();
+ mv.visitJumpInsn(IFNULL, endif2);
+
+ for (String methodId : m_methods) {
+ if (!methodId.equals("<init>")) {
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitLdcInsn(methodId);
+ mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z", true);
+ Label l3 = new Label();
+ mv.visitJumpInsn(IFEQ, l3);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitInsn(ICONST_1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, METHOD_FLAG_PREFIX + methodId, "Z");
+ mv.visitLabel(l3);
+ }
+ }
+
+ mv.visitLabel(endif2);
+ mv.visitInsn(RETURN);
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the getComponentInstance method.
+ */
+ private void createGetComponentInstanceMethod() {
+ MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getComponentInstance", "()Lorg/apache/felix/ipojo/ComponentInstance;", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create a getter method for an array.
+ * @param name : field name
+ * @param desc : method description
+ */
+ private void createArraySetter(String name, String desc) {
+ MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);
+ mv.visitCode();
+
+ String internalType = desc.substring(1);
+ internalType = internalType.substring(0, internalType.length() - 2);
+
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l2 = new Label();
+ mv.visitJumpInsn(IFNE, l2);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalType);
+ mv.visitInsn(RETURN);
+ mv.visitLabel(l2);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ mv.visitInsn(RETURN);
+
+ // End
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create a setter method for an array.
+ * @param name : field name
+ * @param desc : method description
+ */
+ private void createArrayGetter(String name, String desc) {
+ String methodName = "__get" + name;
+ MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
+ mv.visitCode();
+
+ String internalType = desc.substring(2);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);
+ mv.visitInsn(ARETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
+ "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitTypeInsn(CHECKCAST, internalType);
+ mv.visitInsn(ARETURN);
+
+ // End
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the getter for a field.
+ * @param name : field of the dependency
+ * @param desc : description of the getter method
+ * @param type : type to return
+ */
+ private void createSimpleGetter(String name, String desc, Type type) {
+ String methodName = "__get" + name;
+ MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
+ mv.visitCode();
+
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ case Type.INT:
+
+ String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ String unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitInsn(IRETURN);
+
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
+ mv.visitInsn(type.getOpcode(IRETURN));
+ break;
+
+ case Type.LONG:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitInsn(LRETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
+ mv.visitInsn(LRETURN);
+
+ break;
+
+ case Type.DOUBLE:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitInsn(DRETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
+ mv.visitInsn(DRETURN);
+
+ break;
+
+ case Type.FLOAT:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitInsn(FRETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
+ mv.visitInsn(FRETURN);
+
+ break;
+
+ case Type.OBJECT:
+ l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ l1 = new Label();
+ mv.visitJumpInsn(IFNE, l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");
+ mv.visitInsn(ARETURN);
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
+ mv.visitTypeInsn(CHECKCAST, type.getInternalName());
+ mv.visitInsn(ARETURN);
+
+ break;
+
+ default:
+ ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE, "Manipulation problem in " + m_owner + " : a type is not implemented : " + type);
+ break;
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the setter method for one property. The name of the method is _set+name of the field
+ * @param name : name of the field representing a property
+ * @param desc : description of the setter method
+ * @param type : type of the property
+ */
+ private void createSimpleSetter(String name, String desc, Type type) {
+ MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);
+ mv.visitCode();
+
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ case Type.INT:
+ case Type.FLOAT:
+ String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l22 = new Label();
+ mv.visitJumpInsn(IFNE, l22);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
+ mv.visitInsn(RETURN);
+ mv.visitLabel(l22);
+
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V", false);
+ mv.visitVarInsn(ASTORE, 2);
+
+ Label l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ Label l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitInsn(RETURN);
+ break;
+
+ case Type.LONG:
+ case Type.DOUBLE:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+
+ l1 = new Label();
+ mv.visitLabel(l1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l23 = new Label();
+ mv.visitJumpInsn(IFNE, l23);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
+ mv.visitInsn(RETURN);
+ mv.visitLabel(l23);
+
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V", false);
+ mv.visitVarInsn(ASTORE, 3); // Double space
+
+ l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ SET, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitInsn(RETURN);
+ break;
+
+ case Type.OBJECT:
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
+ Label l24 = new Label();
+ mv.visitJumpInsn(IFNE, l24);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, "L" + type.getInternalName() + ";");
+ mv.visitInsn(RETURN);
+ mv.visitLabel(l24);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ mv.visitInsn(RETURN);
+ break;
+ default:
+ ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE, "Manipulation Error : Cannot create the setter method for the field : " + name + " (" + type + ")");
+ break;
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
new file mode 100644
index 0000000..94b1205
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -0,0 +1,287 @@
+/*
+ * 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.manipulation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.GeneratorAdapter;
+
+import java.util.Set;
+
+
+/**
+ * Constructor Adapter.
+ * This class adds an instance manager argument (so switch variable index).
+ * Moreover, it adapts field accesses to delegate accesses to the instance
+ * manager if needed.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {
+
+ /**
+ * The class containing the field.
+ * m_owner : String
+ */
+ private String m_owner;
+
+ /**
+ * Is the super call detected ?
+ */
+ private boolean m_superDetected;
+
+ /**
+ * The super class.
+ */
+ private String m_superClass;
+
+ /**
+ * Set of contained fields.
+ */
+ private Set<String> m_fields;
+
+
+ /**
+ * PropertyCodeAdapter constructor.
+ * A new FiledCodeAdapter should be create for each method visit.
+ *
+ * @param mv the MethodVisitor
+ * @param owner the name of the class
+ * @param fields the list of contained fields
+ * @param access the constructor access
+ * @param desc the constructor descriptor
+ * @param name the name
+ */
+ public ConstructorCodeAdapter(final MethodVisitor mv, final String owner, Set<String> fields, int access, String name, String desc, String superClass) {
+ super(Opcodes.ASM5, mv, access, name, desc);
+ m_owner = owner;
+ m_superDetected = false;
+ m_fields = fields;
+ m_superClass = superClass;
+ }
+
+ /**
+ * Visits an annotation.
+ * If the annotation is visible, the annotation is removed. In fact
+ * the annotation was already moved to the method replacing this one.
+ * If the annotation is not visible, this annotation is kept on this method.
+ *
+ * @param name the name of the annotation
+ * @param visible the annotation visibility
+ * @return the <code>null</code> if the annotation is visible, otherwise returns
+ * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ // Annotations are moved to the injected constructor.
+ if (visible) {
+ return null;
+ } else {
+ return super.visitAnnotation(name, false);
+ }
+ }
+
+ /**
+ * Visits a parameter annotation.
+ * Parameter annotations are moved to replacing constructor except
+ * they are injection annotations(-@Property and -@Requires).
+ * Because injection annotations shouldn't be copied to generated one
+ * in case of re-manipulation, since this is caused to wrong type resolution
+ * of injected parameters.
+ *
+ * @param parameter parameter index
+ * @param desc annotation description(annotation name)
+ * @param visible is parameter annotation visible
+ * @return @AnnotationVisitor
+ */
+ public AnnotationVisitor visitParameterAnnotation(
+ final int parameter,
+ final String desc,
+ final boolean visible) {
+
+ /*
+ * Generated constructor shouldn't inherit injection annotations
+ */
+ if (desc.equals("Lorg/apache/felix/ipojo/annotations/Property;")
+ || desc.equals("Lorg/apache/felix/ipojo/annotations/Requires;")
+ || Names.isCustomAnnotation(desc)) {
+ return null;
+ } else {
+ return super.visitParameterAnnotation(parameter, desc, visible);
+ }
+
+ }
+
+
+ /**
+ * Adapts field accesses.
+ * If the field is owned by the visited class:
+ * <ul>
+ * <li><code>GETFIELD</code> are changed to a <code>__getX</code> invocation.</li>
+ * <li><code>SETFIELD</code> are changed to a <code>__setX</code> invocation.</li>
+ * </ul>
+ *
+ * @param opcode the visited operation code
+ * @param owner the owner of the field
+ * @param name the name of the field
+ * @param desc the descriptor of the field
+ * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)
+ */
+ public void visitFieldInsn(
+ final int opcode,
+ final String owner,
+ final String name,
+ final String desc) {
+ if (m_fields.contains(name) && m_owner.equals(owner)) {
+ if (opcode == GETFIELD) {
+ String gDesc = "()" + desc;
+ mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc, false);
+ return;
+ } else if (opcode == PUTFIELD) {
+ String sDesc = "(" + desc + ")V";
+ mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc, false);
+ return;
+ }
+ }
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ /**
+ * Visits a method invocation instruction.
+ * After the super constructor invocation, insert the _setComponentManager invocation.
+ * Otherwise, the method invocation doesn't change
+ *
+ * @param opcode the opcode
+ * @param owner the class owning the invoked method
+ * @param name the method name
+ * @param desc the method descriptor
+ * @param itf if the method's owner class is an interface
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+
+ // A method call is detected, check if it is the super call :
+ // the first init is not necessary the super call, so check that it is really the super class.
+ if (!m_superDetected && name.equals("<init>") && owner.equals(m_superClass)) {
+ m_superDetected = true;
+ // The first invocation is the super call
+ // 1) Visit the super constructor :
+
+ //mv.visitVarInsn(ALOAD, 0); The ALOAD 0 was already visited. This previous visit allows
+ // Super constructor parameters.
+ mv.visitMethodInsn(opcode, owner, name, desc, false); // Super constructor invocation
+
+ // 2) Load the object and the component manager argument
+ mv.visitVarInsn(ALOAD, 0);
+ //mv.visitVarInsn(ALOAD, Type.getArgumentTypes(m_constructorDesc).length);
+ mv.visitVarInsn(ALOAD, 1); // CM is always the first argument
+ // 3) Initialize the field
+ mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setInstanceManager",
+ "(Lorg/apache/felix/ipojo/InstanceManager;)V", false);
+
+ } else {
+ if (opcode == INVOKEINTERFACE) {
+ mv.visitMethodInsn(opcode, owner, name, desc, true);
+ } else {
+ mv.visitMethodInsn(opcode, owner, name, desc, false);
+ }
+ }
+ }
+
+ /**
+ * Visits a variable instruction.
+ * This method increments the variable index if
+ * it is not <code>this</code> (i.e. 0). This increment
+ * is due to the instance manager parameter added in the method
+ * signature.
+ *
+ * @param opcode the opcode
+ * @param var the variable index
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitVarInsn(int, int)
+ */
+ public void visitVarInsn(int opcode, int var) {
+ if (var == 0) {
+ mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)
+ } else {
+ mv.visitVarInsn(opcode, var + 1); // All other variable index must be incremented (due to
+ // the instance manager argument
+ }
+
+ }
+
+ /**
+ * Visits an increment instruction.
+ * This method increments the variable index if
+ * it is not <code>this</code> (i.e. 0). This increment
+ * is due to the instance manager parameter added in the method
+ * signature.
+ *
+ * @param var the variable index
+ * @param increment the increment
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitIincInsn(int, int)
+ */
+ public void visitIincInsn(int var, int increment) {
+ if (var != 0) {
+ mv.visitIincInsn(var + 1, increment);
+ } else {
+ mv.visitIincInsn(var, increment); // Increment the current object ???
+ }
+ }
+
+ /**
+ * Visits a local variable.
+ * Adds _manager and increment others variable indexes.
+ * This variable has the same scope than <code>this</code> and
+ * has the <code>1</code> index.
+ *
+ * @param name the variable name
+ * @param desc the variable descriptor
+ * @param signature the variable signature
+ * @param start the beginning label
+ * @param end the ending label
+ * @param index the variable index
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)
+ */
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ if (index == 0) {
+ mv.visitLocalVariable(name, desc, signature, start, end, index);
+ mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);
+ } else {
+ mv.visitLocalVariable(name, desc, signature, start, end, index + 1);
+ }
+ }
+
+ /**
+ * Visit max method.
+ * The stack size is incremented of 1. The
+ * local variable count is incremented of 2.
+ *
+ * @param maxStack the stack size.
+ * @param maxLocals the local variable count.
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitMaxs(int, int)
+ */
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv.visitMaxs(maxStack + 1, maxLocals + 2);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
new file mode 100644
index 0000000..ecdc9ef
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
@@ -0,0 +1,341 @@
+/*
+ * 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.manipulation;
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.tree.LocalVariableNode;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Adapts a inner class in order to allow accessing outer class fields.
+ * A manipulated inner class has access to the managed field of the outer class.
+ *
+ * Only non-static inner classes are manipulated, others are not.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InnerClassAdapter extends ClassVisitor implements Opcodes {
+
+ /**
+ * The manipulator having manipulated the outer class.
+ * We add method descriptions to this manipulator.
+ */
+ private final Manipulator m_manipulator;
+
+ /**
+ * The name of the inner class. This name is only define in the outer class.
+ */
+ private final String m_name;
+
+ /**
+ * The ismple name of the class.
+ */
+ private final String m_simpleName;
+
+ /**
+ * Implementation class name.
+ */
+ private String m_outer;
+ /**
+ * List of fields of the implementation class.
+ */
+ private Set<String> m_fields;
+
+ /**
+ * Creates the inner class adapter.
+ *
+ * @param name the inner class name (internal name)
+ * @param visitor parent class visitor
+ * @param outerClassName outer class (implementation class)
+ * @param manipulator the manipulator having manipulated the outer class.
+ */
+ public InnerClassAdapter(String name, ClassVisitor visitor, String outerClassName,
+ Manipulator manipulator) {
+ super(Opcodes.ASM5, visitor);
+ m_name = name;
+ m_simpleName = m_name.substring(m_name.indexOf("$") + 1);
+ m_outer = outerClassName;
+ m_manipulator = manipulator;
+ m_fields = manipulator.getFields().keySet();
+ }
+
+ /**
+ * Visits a method.
+ * This methods create a code visitor manipulating outer class field accesses.
+ *
+ * @param access method visibility
+ * @param name method name
+ * @param desc method descriptor
+ * @param signature method signature
+ * @param exceptions list of exceptions thrown by the method
+ * @return a code adapter manipulating field accesses
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.String[])
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ // Do nothing on static methods, should not happen in non-static inner classes.
+ if ((access & ACC_STATIC) == ACC_STATIC) {
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ // Do nothing on native methods
+ if ((access & ACC_NATIVE) == ACC_NATIVE) {
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+
+ // Do not re-manipulate.
+ if (! m_manipulator.isAlreadyManipulated()) {
+
+ if (name.equals("<init>")) {
+ // We change the field access from the constructor, but we don't generate the wrapper.
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ return new MethodCodeAdapter(mv, m_outer, access, name, desc, m_fields);
+ }
+
+ // For all non constructor methods
+
+ MethodDescriptor md = getMethodDescriptor(name, desc);
+ if (md == null) {
+ generateMethodWrapper(access, name, desc, signature, exceptions, null, null,
+ null);
+ } else {
+ generateMethodWrapper(access, name, desc, signature, exceptions,
+ md.getArgumentLocalVariables(),
+ md.getAnnotations(), md.getParameterAnnotations());
+ }
+
+ // The new name is the method name prefixed by the PREFIX.
+ MethodVisitor mv = super.visitMethod(ACC_PRIVATE, ClassManipulator.PREFIX + name, desc, signature,
+ exceptions);
+ return new MethodCodeAdapter(mv, m_outer, ACC_PRIVATE, ClassManipulator.PREFIX + name, desc, m_fields);
+ } else {
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+ }
+
+ private String getMethodFlagName(String name, String desc) {
+ return ClassManipulator.METHOD_FLAG_PREFIX + getMethodId(name, desc);
+ }
+
+ private String getMethodId(String name, String desc) {
+ StringBuilder id = new StringBuilder(m_simpleName);
+ id.append("___"); // Separator
+ id.append(name);
+
+ Type[] args = Type.getArgumentTypes(desc);
+ for (Type type : args) {
+ String arg = type.getClassName();
+ if (arg.endsWith("[]")) {
+ // We have to replace all []
+ String acc = "";
+ while (arg.endsWith("[]")) {
+ arg = arg.substring(0, arg.length() - 2);
+ acc += "__";
+ }
+ id.append("$").append(arg.replace('.', '_')).append(acc);
+ } else {
+ id.append("$").append(arg.replace('.', '_'));
+ }
+ }
+ return id.toString();
+ }
+
+ /**
+ * Generate the method header of a POJO method.
+ * This method header encapsulate the POJO method call to
+ * signal entry exit and error to the container.
+ *
+ * The instance manager and flag are accessed using method calls.
+ * @param access : access flag.
+ * @param name : method name.
+ * @param desc : method descriptor.
+ * @param signature : method signature.
+ * @param exceptions : declared exceptions.
+ * @param localVariables : the local variable nodes.
+ * @param annotations : the annotations to move to this method.
+ * @param paramAnnotations : the parameter annotations to move to this method.
+ */
+ private void generateMethodWrapper(int access, String name, String desc, String signature, String[] exceptions,
+ List<LocalVariableNode> localVariables, List<ClassChecker.AnnotationDescriptor> annotations,
+ Map<Integer, List<ClassChecker.AnnotationDescriptor>> paramAnnotations) {
+ GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc);
+
+ // If we have variables, we wraps the code within labels. The `lifetime` of the variables are bound to those
+ // two variables.
+ boolean hasArgumentLabels = localVariables != null && !localVariables.isEmpty();
+ Label start = null;
+ if (hasArgumentLabels) {
+ start = new Label();
+ mv.visitLabel(start);
+ }
+
+ mv.visitCode();
+
+ Type returnType = Type.getReturnType(desc);
+
+ // Compute result and exception stack location
+ int result = -1;
+ int exception;
+
+ //int arguments = mv.newLocal(Type.getType((new Object[0]).getClass()));
+
+ if (returnType.getSort() != Type.VOID) {
+ // The method returns something
+ result = mv.newLocal(returnType);
+ exception = mv.newLocal(Type.getType(Throwable.class));
+ } else {
+ exception = mv.newLocal(Type.getType(Throwable.class));
+ }
+
+ Label l0 = new Label();
+ Label l1 = new Label();
+ Label l2 = new Label();
+
+ mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");
+
+ // Access the flag from the outer class
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_name, "this$0", "L" + m_outer + ";");
+ mv.visitFieldInsn(GETFIELD, m_outer, getMethodFlagName(name, desc), "Z");
+ mv.visitJumpInsn(IFNE, l0);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.loadArgs();
+ mv.visitMethodInsn(INVOKESPECIAL, m_name, ClassManipulator.PREFIX + name, desc, false);
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+
+ // end of the non intercepted method invocation.
+
+ mv.visitLabel(l0);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_name, "this$0", "L" + m_outer + ";");
+ mv.visitFieldInsn(GETFIELD, m_outer, ClassManipulator.IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(getMethodId(name, desc));
+ mv.loadArgArray();
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ClassManipulator.ENTRY,
+ "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V", false);
+
+ mv.visitVarInsn(ALOAD, 0);
+
+ // Do not allow argument modification : just reload arguments.
+ mv.loadArgs();
+ mv.visitMethodInsn(INVOKESPECIAL, m_name, ClassManipulator.PREFIX + name, desc, false);
+
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ISTORE), result);
+ }
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_name, "this$0", "L" + m_outer + ";");
+ mv.visitFieldInsn(GETFIELD, m_outer, ClassManipulator.IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(getMethodId(name, desc));
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
+ mv.box(returnType);
+ } else {
+ mv.visitInsn(ACONST_NULL);
+ }
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager",
+ ClassManipulator.EXIT, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);
+
+ mv.visitLabel(l1);
+ Label l7 = new Label();
+ mv.visitJumpInsn(GOTO, l7);
+ mv.visitLabel(l2);
+
+ mv.visitVarInsn(ASTORE, exception);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_name, "this$0", "L" + m_outer + ";");
+ mv.visitFieldInsn(GETFIELD, m_outer, ClassManipulator.IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitLdcInsn(getMethodId(name, desc));
+ mv.visitVarInsn(ALOAD, exception);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ClassManipulator.ERROR,
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V", false);
+ mv.visitVarInsn(ALOAD, exception);
+ mv.visitInsn(ATHROW);
+
+ mv.visitLabel(l7);
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
+ }
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+
+ // If we had arguments, we mark the end of the lifetime.
+ Label end = null;
+ if (hasArgumentLabels) {
+ end = new Label();
+ mv.visitLabel(end);
+ }
+
+ // Move annotations
+ if (annotations != null) {
+ for (ClassChecker.AnnotationDescriptor ad : annotations) {
+ ad.visitAnnotation(mv);
+ }
+ }
+
+ // Move parameter annotations
+ if (paramAnnotations != null && ! paramAnnotations.isEmpty()) {
+ for (Integer id : paramAnnotations.keySet()) {
+ List<ClassChecker.AnnotationDescriptor> ads = paramAnnotations.get(id);
+ for (ClassChecker.AnnotationDescriptor ad : ads) {
+ ad.visitParameterAnnotation(id, mv);
+ }
+ }
+ }
+
+ // Write the arguments name.
+ if (hasArgumentLabels) {
+ for (LocalVariableNode var : localVariables) {
+ mv.visitLocalVariable(var.name, var.desc, var.signature, start, end, var.index);
+ }
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Gets the method descriptor for the specified name and descriptor.
+ * The method descriptor is looked inside the
+ * {@link ClassManipulator#m_visitedMethods}
+ * @param name the name of the method
+ * @param desc the descriptor of the method
+ * @return the method descriptor or <code>null</code> if not found.
+ */
+ private MethodDescriptor getMethodDescriptor(String name, String desc) {
+ for (MethodDescriptor md : m_manipulator.getMethodsFromInnerClass(m_name)) {
+ if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {
+ return md;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassChecker.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassChecker.java
new file mode 100644
index 0000000..886dea2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassChecker.java
@@ -0,0 +1,61 @@
+/*
+ * 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.manipulation;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Analyze an inner class.
+ * This visit collects the methods from the inner class.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InnerClassChecker extends ClassVisitor implements Opcodes {
+
+ private final String m_name;
+ private final Manipulator m_manipulator;
+
+ public InnerClassChecker(String name, Manipulator manipulator) {
+ super(Opcodes.ASM5);
+ m_name = name;
+ m_manipulator = manipulator;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ // Do not collect static and native method.
+ if ((access & ACC_STATIC) == ACC_STATIC) {
+ return null;
+ }
+
+ if ((access & ACC_NATIVE) == ACC_NATIVE) {
+ return null;
+ }
+
+ // Don't add generated methods, and constructors
+ if (!ClassChecker.isGeneratedMethod(name, desc) && ! name.endsWith("<init>")) {
+ final MethodDescriptor md = new MethodDescriptor(name, desc, (access & ACC_STATIC) == ACC_STATIC);
+ m_manipulator.addMethodToInnerClass(m_name, md);
+ }
+
+ return null;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
new file mode 100644
index 0000000..76b083f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
@@ -0,0 +1,124 @@
+/*
+ * 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.manipulation;
+
+/**
+ * Store properties for the manipulation process.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class ManipulationProperty {
+
+ /**
+ * Logger info level.
+ */
+ public static final int INFO = 0;
+
+ /**
+ * Logger warning level.
+ */
+ public static final int WARNING = 1;
+
+ /**
+ * Logger severe level.
+ */
+ public static final int SEVERE = 2;
+
+ /**
+ * Activator internal package name.
+ */
+ protected static final String IPOJO_INTERNAL_PACKAGE_NAME = "org/apache/felix/ipojo/";
+
+ /**
+ * Ipojo internal package name for internal descriptor.
+ */
+ protected static final String IPOJO_INTERNAL_DESCRIPTOR = "L" + IPOJO_INTERNAL_PACKAGE_NAME;
+
+ /**
+ * iPOJO Package name.
+ */
+ protected static final String IPOJO_PACKAGE_NAME = "org.apache.felix.ipojo";
+
+ /**
+ * Helper array for byte code manipulation of primitive type.
+ */
+ static final String[][] PRIMITIVE_BOXING_INFORMATION = new String[][] {
+ {"V", "ILLEGAL", "ILLEGAL"},
+ {"Z", "java/lang/Boolean", "booleanValue"},
+ {"C", "java/lang/Character", "charValue"},
+ {"B", "java/lang/Byte", "byteValue"},
+ {"S", "java/lang/Short", "shortValue"},
+ {"I", "java/lang/Integer", "intValue"},
+ {"F", "java/lang/Float", "floatValue"},
+ {"J", "java/lang/Long", "longValue"},
+ {"D", "java/lang/Double", "doubleValue"}
+ };
+
+ /**
+ * Internal logger implementation.
+ */
+ protected static class Logger {
+ /**
+ * Log method.
+ * @param level : level
+ * @param message : message to log
+ */
+ public void log(int level, String message) {
+ if (level >= LOG_LEVEL) {
+ switch (level) {
+ case INFO:
+ System.err.println("[INFO] " + message);
+ break;
+ case WARNING:
+ System.err.println("[WARNING] " + message);
+ break;
+ case SEVERE:
+ System.err.println("[SEVERE] " + message);
+ break;
+ default:
+ System.err.println("[SEVERE] " + message);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Manipulator logger.
+ */
+ private static Logger LOGGER;
+
+ /**
+ * Default logger level.
+ */
+ private static int LOG_LEVEL = WARNING;
+
+
+ /**
+ * Get the manipulator logger.
+ * @return the logger used by the manipulator.
+ */
+ public static Logger getLogger() {
+ if (LOGGER == null) {
+ LOGGER = new Logger();
+ }
+ return LOGGER;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
new file mode 100644
index 0000000..ba3a4e2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -0,0 +1,304 @@
+/*
+ * 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.manipulation;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.util.CheckClassAdapter;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * iPOJO Byte code Manipulator.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class Manipulator {
+ /**
+ * A classloader used to compute frames.
+ */
+ private final ClassLoader m_classLoader;
+ /**
+ * Store the visited fields : [name of the field, type of the field].
+ */
+ private Map<String, String> m_fields;
+
+ /**
+ * Store the interface implemented by the class.
+ */
+ private List<String> m_interfaces;
+
+ /**
+ * Store the methods list.
+ */
+ private List<MethodDescriptor> m_methods;
+
+ /**
+ * Pojo super class.
+ */
+ private String m_superClass;
+
+ /**
+ * List of owned inner classes and internal methods.
+ */
+ private Map<String, List<MethodDescriptor>> m_inners;
+
+ /**
+ * Java byte code version.
+ */
+ private int m_version;
+
+ /**
+ * Was the class already manipulated.
+ */
+ private boolean m_alreadyManipulated;
+
+ /**
+ * The manipulated class name.
+ */
+ private String m_className;
+
+ public Manipulator(ClassLoader loader) {
+ // No classloader set, use current one.
+ m_classLoader = loader;
+ }
+
+ /**
+ * Checks the given bytecode, determines if the class was already manipulated, and collect the metadata about the
+ * class.
+ * @param origin the bytecode
+ */
+ public void prepare(byte[] origin) throws IOException {
+ InputStream is = new ByteArrayInputStream(origin);
+
+ // First check if the class is already manipulated :
+ ClassReader ckReader = new ClassReader(is);
+ ClassChecker ck = new ClassChecker();
+ ckReader.accept(ck, ClassReader.SKIP_FRAMES);
+ is.close();
+
+ m_fields = ck.getFields(); // Get visited fields (contains only POJO fields)
+ m_className = ck.getClassName();
+
+ // Get interfaces and super class.
+ m_interfaces = ck.getInterfaces();
+ m_superClass = ck.getSuperClass();
+
+ // Get the methods list
+ m_methods = ck.getMethods();
+
+ // Methods are not yet collected, but the structure is ready.
+ m_inners = ck.getInnerClassesAndMethods();
+
+ m_version = ck.getClassVersion();
+
+ m_alreadyManipulated = ck.isAlreadyManipulated();
+ }
+
+ /**
+ * Manipulate the given byte array.
+ * @param origin : original class.
+ * @return the manipulated class, if the class is already manipulated, the original class.
+ * @throws IOException : if an error occurs during the manipulation.
+ */
+ public byte[] manipulate(byte[] origin) throws IOException {
+ if (!m_alreadyManipulated) {
+ InputStream is2 = new ByteArrayInputStream(origin);
+ ClassReader reader = new ClassReader(is2);
+ ClassWriter writer = new ClassLoaderAwareClassWriter(ClassWriter.COMPUTE_FRAMES, m_className, m_superClass,
+ m_classLoader);
+ ClassManipulator process = new ClassManipulator(new CheckClassAdapter(writer, false), this);
+ if (m_version >= Opcodes.V1_6) {
+ reader.accept(process, ClassReader.EXPAND_FRAMES);
+ } else {
+ reader.accept(process, 0);
+ }
+ is2.close();
+ return writer.toByteArray();
+ } else {
+ return origin;
+ }
+ }
+
+ /**
+ * Checks whether the class was already manipulated.
+ * @return {@code true} if the class was already manipulated, {@code false} otherwise
+ */
+ public boolean isAlreadyManipulated() {
+ return m_alreadyManipulated;
+ }
+
+ public static String toQualifiedName(String clazz) {
+ return clazz.replace("/", ".");
+ }
+
+ /**
+ * Compute component type manipulation metadata.
+ * @return the manipulation metadata of the class.
+ */
+ public Element getManipulationMetadata() {
+ Element elem = new Element("Manipulation", "");
+
+ elem.addAttribute(new Attribute("className", toQualifiedName(m_className)));
+
+ if (m_superClass != null) {
+ elem.addAttribute(new Attribute("super", m_superClass));
+ }
+
+ for (String m_interface : m_interfaces) {
+ Element itf = new Element("Interface", "");
+ Attribute att = new Attribute("name", m_interface);
+ itf.addAttribute(att);
+ elem.addElement(itf);
+ }
+
+ for (Map.Entry<String, String> f : m_fields.entrySet()) {
+ Element field = new Element("Field", "");
+ Attribute attName = new Attribute("name", f.getKey());
+ Attribute attType = new Attribute("type", f.getValue());
+ field.addAttribute(attName);
+ field.addAttribute(attType);
+ elem.addElement(field);
+ }
+
+ for (MethodDescriptor method : m_methods) {
+ elem.addElement(method.getElement());
+ }
+
+ for (Map.Entry<String, List<MethodDescriptor>> inner : m_inners.entrySet()) {
+ Element element = new Element("Inner", "");
+ Attribute name = new Attribute("name", extractInnerClassName(toQualifiedName(inner.getKey())));
+ element.addAttribute(name);
+
+ for (MethodDescriptor method : inner.getValue()) {
+ element.addElement(method.getElement());
+ }
+ elem.addElement(element);
+ }
+
+ return elem;
+ }
+
+ /**
+ * Extracts the inner class simple name from the qualified name. It extracts the part after the `$` character.
+ * @param clazz the qualified class name
+ * @return the simple inner class name
+ */
+ public static String extractInnerClassName(String clazz) {
+ if (!clazz.contains("$")) {
+ return clazz;
+ } else {
+ return clazz.substring(clazz.indexOf("$") +1);
+ }
+ }
+
+ public Map<String, String> getFields() {
+ return m_fields;
+ }
+
+ public List<MethodDescriptor> getMethods() {
+ return m_methods;
+ }
+
+ public Collection<String> getInnerClasses() {
+ return new ArrayList<String>(m_inners.keySet());
+ }
+
+ public int getClassVersion() {
+ return m_version;
+ }
+
+ /**
+ * Adds a method to an inner class.
+ * @param name the inner class name
+ * @param md the method descriptor to add
+ */
+ public void addMethodToInnerClass(String name, MethodDescriptor md) {
+ List<MethodDescriptor> list = m_inners.get(name);
+ if (list == null) {
+ list = new ArrayList<MethodDescriptor>();
+ m_inners.put(name, list);
+ }
+ list.add(md);
+ }
+
+ /**
+ * Analyzes the given inner class.
+ * @param inner the inner class name
+ * @param bytecode the bytecode of the inner class
+ */
+ public void prepareInnerClass(String inner, byte[] bytecode) throws IOException {
+ InputStream is = new ByteArrayInputStream(bytecode);
+ ClassReader ckReader = new ClassReader(is);
+ InnerClassChecker ck = new InnerClassChecker(inner, this);
+ ckReader.accept(ck, ClassReader.SKIP_FRAMES);
+ is.close();
+ // The metadata are collected during the visit.
+ }
+
+ /**
+ * Manipulates the inner class. If the outer class was already manipulated does not re-manipulate the inner class.
+ * We consider that the manipulation cycle of the outer and inner classes are the same.
+ * @param inner the inner class name
+ * @param bytecode input (i.e. original) class
+ * @return the manipulated class
+ * @throws IOException the class cannot be read correctly
+ */
+ public byte[] manipulateInnerClass(String inner, byte[] bytecode) throws IOException {
+ if (!m_alreadyManipulated) {
+ InputStream is1 = new ByteArrayInputStream(bytecode);
+
+ ClassReader cr = new ClassReader(is1);
+ ClassWriter cw = new ClassLoaderAwareClassWriter(ClassWriter.COMPUTE_FRAMES, inner, null, m_classLoader);
+ InnerClassAdapter adapter = new InnerClassAdapter(inner, cw, m_className, this);
+ if (m_version >= Opcodes.V1_6) {
+ cr.accept(adapter, ClassReader.EXPAND_FRAMES);
+ } else {
+ cr.accept(adapter, 0);
+ }
+ is1.close();
+
+ return cw.toByteArray();
+ } else {
+ // Return the unchanged inner class
+ return bytecode;
+ }
+ }
+
+ public List<MethodDescriptor> getMethodsFromInnerClass(String innerClassInternalName) {
+ return m_inners.get(innerClassInternalName);
+ }
+
+ public Map<String, List<MethodDescriptor>> getInnerClassesAndMethods() {
+ // Transform the map to use the simple name of the inner classes.
+ Map<String, List<MethodDescriptor>> map = new HashMap<String, List<MethodDescriptor>>();
+ for (Map.Entry<String, List<MethodDescriptor>> entry : m_inners.entrySet()) {
+ String name = extractInnerClassName(toQualifiedName(entry.getKey()));
+ map.put(name, entry.getValue());
+ }
+ return map;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
new file mode 100644
index 0000000..5b24026
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
@@ -0,0 +1,122 @@
+/*
+ * 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.manipulation;
+
+import java.util.Set;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.GeneratorAdapter;
+
+/**
+ * Insert code calling callbacks at the entry and before the exit of a method.
+ * Moreover it replaces all GETFIELD and SETFIELD by getter and setter invocation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodCodeAdapter extends GeneratorAdapter implements Opcodes {
+
+ /**
+ * The owner class of the field. m_owner : String
+ */
+ private String m_owner;
+
+ /**
+ * Contained fields.
+ */
+ private Set<String> m_fields;
+
+ /**
+ * MethodCodeAdapter constructor.
+ * @param mv : MethodVisitor
+ * @param owner : Name of the class
+ * @param access : Method access
+ * @param name : Method name
+ * @param desc : Method descriptor
+ * @param fields : Contained fields
+ */
+ public MethodCodeAdapter(final MethodVisitor mv, final String owner, int access, String name, String desc, Set<String> fields) {
+ super(Opcodes.ASM5, mv, access, name, desc);
+ m_owner = owner;
+ m_fields = fields;
+ }
+
+ /**
+ * Visit an instruction modifying a method (GETFIELD/PUTFIELD).
+ * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)
+ * @param opcode : visited operation code
+ * @param owner : owner of the field
+ * @param name : name of the field
+ * @param desc : descriptor of the field
+ */
+ public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
+ if (owner.equals(m_owner) && m_fields.contains(name)) {
+ if (opcode == GETFIELD) {
+ String gDesc = "()" + desc;
+ visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc, false);
+ return;
+ } else if (opcode == PUTFIELD) {
+ String sDesc = "(" + desc + ")V";
+ visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc, false);
+ return;
+ }
+ }
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ /**
+ * Visits an annotation.
+ * If the annotation is visible, the annotation is removed. In fact
+ * the annotation was already moved to the method replacing this one.
+ * If the annotation is not visible, this annotation is kept on this method.
+ * @param name the name of the annotation
+ * @param visible the annotation visibility
+ * @return the <code>null</code> if the annotation is visible, otherwise returns
+ * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String name, boolean visible) {
+ // Annotations are moved to the injected constructor.
+ if (visible) {
+ return null;
+ } else {
+ return super.visitAnnotation(name, false);
+ }
+ }
+
+ /**
+ * Visits a parameter annotation.
+ * @param id the parameter number.
+ * @param name the annotation name
+ * @param visible if te annotation visibility
+ * @return the <code>null</code> if the annotation is visible, otherwise returns
+ * {@link GeneratorAdapter#visitAnnotation(String, boolean)}
+ * @see org.objectweb.asm.commons.GeneratorAdapter#visitParameterAnnotation(int, java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitParameterAnnotation(int id, String name,
+ boolean visible) {
+ if (visible) {
+ return null;
+ } else {
+ return super.visitParameterAnnotation(id, name, false);
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
new file mode 100644
index 0000000..28e9ccd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -0,0 +1,264 @@
+/*
+ * 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.manipulation;
+
+import java.util.*;
+
+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.LocalVariableNode;
+
+/**
+ * Method Descriptor describe a method.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodDescriptor {
+ /**
+ * Method name.
+ */
+ private final String m_name;
+
+ /**
+ * Returned type.
+ */
+ private final String m_returnType;
+
+ /**
+ * Argument types.
+ */
+ private final String[] m_arguments;
+
+ /**
+ * The descriptor of the method.
+ */
+ private final String m_desc;
+
+
+ /**
+ * The list of {@link AnnotationDescriptor} attached to this
+ * method.
+ */
+ private List<AnnotationDescriptor> m_annotations;
+
+ /**
+ * The association argument (number) - {@link AnnotationDescriptor}.
+ */
+ private Map<Integer, List<AnnotationDescriptor>> m_parameterAnnotations = new HashMap<Integer, List<AnnotationDescriptor>>();
+
+ /**
+ * The arguments variables.
+ */
+ private List<LocalVariableNode> m_argLocalVariables;
+
+ /**
+ * The stack size to keep of the arguments.
+ */
+ private final int m_argsVarLength;
+
+ /**
+ * Flag indicating is the described method is static.
+ */
+ private final boolean m_isStatic;
+
+ /**
+ * The local variables by index.
+ * This map is used to detect the argument names.
+ */
+ private LinkedHashMap<Integer, LocalVariableNode> m_locals = new LinkedHashMap<Integer, LocalVariableNode>();
+
+ /**
+ * Constructor.
+ * @param name : name of the method.
+ * @param desc : descriptor of the method.
+ * @param isStatic : is the method static
+ */
+ public MethodDescriptor(String name, String desc, boolean isStatic) {
+ m_name = name;
+ m_desc = desc;
+ m_isStatic = isStatic;
+ Type ret = Type.getReturnType(desc);
+ Type[] args = Type.getArgumentTypes(desc);
+
+ m_returnType = getType(ret);
+ m_arguments = new String[args.length];
+ int argsVarLength = args.length;
+ if (!m_isStatic) {
+ argsVarLength++;
+ }
+ for (int i = 0; i < args.length; i++) {
+ String type = getType(args[i]);
+ m_arguments[i] = type;
+ if ("long".equals(type) || "double".equals(type)) {
+ argsVarLength++;
+ }
+ }
+ m_argsVarLength = argsVarLength;
+ }
+
+ /**
+ * Add an annotation to the current method.
+ * @param ann annotation to add
+ */
+ public void addAnnotation(AnnotationDescriptor ann) {
+ if (m_annotations == null) {
+ m_annotations = new ArrayList<AnnotationDescriptor>();
+ }
+ m_annotations.add(ann);
+ }
+
+ /**
+ * Add an annotation to the current method.
+ * @param ann annotation to add
+ */
+ public void addParameterAnnotation(int id, AnnotationDescriptor ann) {
+ List<AnnotationDescriptor> list = m_parameterAnnotations.get(new Integer(id));
+ if (list == null) {
+ list = new ArrayList<AnnotationDescriptor>();
+ m_parameterAnnotations.put(new Integer(id), list);
+ }
+ list.add(ann);
+ }
+
+ public List<AnnotationDescriptor> getAnnotations() {
+ return m_annotations;
+ }
+
+ public Map<Integer, List<AnnotationDescriptor>> getParameterAnnotations() {
+ return m_parameterAnnotations;
+ }
+
+ public String getDescriptor() {
+ return m_desc;
+ }
+
+ /**
+ * Compute method manipulation metadata.
+ * @return the element containing metadata about this method.
+ */
+ public Element getElement() {
+ Element method = new Element("method", "");
+ method.addAttribute(new Attribute("name", m_name));
+
+ // Add return
+ if (!m_returnType.equals("void")) {
+ method.addAttribute(new Attribute("return", m_returnType));
+ }
+
+ // Add arguments
+ if (m_arguments.length > 0) {
+ StringBuilder args = new StringBuilder("{");
+ StringBuilder names = new StringBuilder("{");
+ args.append(m_arguments[0]);
+ if (m_locals.containsKey(1)) {
+ names.append(m_locals.get(1).name); // index +1 as the 0 is this
+ }
+ for (int i = 1; i < m_arguments.length; i++) {
+ args.append(",").append(m_arguments[i]);
+ if (m_locals.containsKey(i +1)) {
+ names.append(",").append(m_locals.get(i +1).name);
+ }
+ }
+ args.append("}");
+ names.append("}");
+
+ method.addAttribute(new Attribute("arguments", args.toString()));
+ method.addAttribute(new Attribute("names", names.toString()));
+ }
+
+ return method;
+ }
+
+ /**
+ * Get the iPOJO internal type for the given type.
+ * @param type : type.
+ * @return the iPOJO internal type.
+ */
+ private String getType(Type type) {
+ switch (type.getSort()) {
+ case Type.ARRAY:
+ // Append brackets.
+ String brackets = "";
+ for (int i = 0; i < type.getDimensions(); i++) {
+ brackets += "[]";
+ }
+ Type elemType = type.getElementType();
+ return getType(elemType) + brackets;
+ case Type.BOOLEAN:
+ return "boolean";
+ case Type.BYTE:
+ return "byte";
+ case Type.CHAR:
+ return "char";
+ case Type.DOUBLE:
+ return "double";
+ case Type.FLOAT:
+ return "float";
+ case Type.INT:
+ return "int";
+ case Type.LONG:
+ return "long";
+ case Type.OBJECT:
+ return type.getClassName();
+ case Type.SHORT:
+ return "short";
+ case Type.VOID:
+ return "void";
+ default:
+ return "unknown";
+ }
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public void addLocalVariable(String name, String desc, String signature, int index) {
+ m_locals.put(index, new LocalVariableNode(name, desc, signature, null, null, index));
+ if (index >= m_argsVarLength) {
+ // keep only argument-related local variables definitions (others relate to code which isn't in this method)
+ return;
+ }
+ if (m_argLocalVariables == null) {
+ m_argLocalVariables = new ArrayList<LocalVariableNode>();
+ }
+ m_argLocalVariables.add(new LocalVariableNode(name, desc, signature, null, null, index));
+ }
+
+ public void end() {
+ if (m_argLocalVariables != null && m_argLocalVariables.size() > 1) {
+ // sort them by index, even if from experience, argument-related variables (and only those) are already sorted
+ Collections.sort(m_argLocalVariables, new Comparator<LocalVariableNode>(){
+ public int compare(LocalVariableNode o1, LocalVariableNode o2) {
+ return o1.index - o2.index;
+ }
+ });
+ }
+ }
+
+ public List<LocalVariableNode> getArgumentLocalVariables() {
+ return m_argLocalVariables;
+ }
+
+ public LinkedHashMap<Integer, LocalVariableNode> getLocals() {
+ return m_locals;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.java
new file mode 100644
index 0000000..c8af7f5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+
+/**
+ * Defines a filter to be tested against Attribute contained
+ * in the Manifest.
+ * If one filter accept the attribute, others are ignored.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestAttributeFilter {
+
+ /**
+ * Tests if the given Attribute is recognized by the filter
+ * @param attribute the tested attribute.
+ * @return <code>true</code> if the filter accept the
+ * value, <code>false</code> otherwise.
+ */
+ public boolean accept(final Attribute attribute);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java
new file mode 100644
index 0000000..9a1a56b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java
@@ -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.manipulator;
+
+import java.util.jar.Manifest;
+
+/**
+ * A {@code ManifestProvider} is responsible of providing the original
+ * {@link Manifest} of the manipulated Bundle.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestProvider {
+
+ /**
+ * Returns the original bundle's Manifest.
+ * @return Manifest of the bundle
+ */
+ Manifest getManifest();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
new file mode 100644
index 0000000..7e72309
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
@@ -0,0 +1,185 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.manipulation.Manipulator;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@code ManipulationEngine} is responsible to drive the component's
+ * classes manipulation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationEngine {
+
+ /**
+ * The classloader given to the manipulator to load classes.
+ */
+ private final ClassLoader m_classLoader;
+ /**
+ * List of component types.
+ */
+ private List<ManipulationUnit> m_manipulationUnits = new ArrayList<ManipulationUnit>();
+
+ /**
+ * Error reporting.
+ */
+ private Reporter m_reporter;
+
+ /**
+ * Bytecode store.
+ */
+ private ResourceStore m_store;
+
+ /**
+ * The visitor handling output result.
+ */
+ private ManipulationVisitor m_manipulationVisitor;
+
+ public ManipulationEngine(ClassLoader classLoader) {
+ m_classLoader = classLoader;
+ }
+
+ /**
+ * Add information related to a discovered component that will be manipulated.
+ * @param component additional component
+ */
+ public void addManipulationUnit(ManipulationUnit component) {
+ m_manipulationUnits.add(component);
+ }
+
+ public void setManipulationVisitor(ManipulationVisitor manipulationVisitor) {
+ m_manipulationVisitor = manipulationVisitor;
+ }
+
+ /**
+ * @param reporter Feedback reporter.
+ */
+ public void setReporter(Reporter reporter) {
+ m_reporter = reporter;
+ }
+
+ /**
+ * Provides the bytecode store that allows to retrieve bytecode of the
+ * component's related resources (inner classes for example).
+ * @param store Helps to locate bytecode for classes.
+ */
+ public void setResourceStore(ResourceStore store) {
+ m_store = store;
+ }
+
+ /**
+ * Manipulates classes of all the given component's.
+ */
+ public void generate() {
+
+ // Iterates over the list of discovered components
+ // Note that this list includes components from metadata.xml AND from annotations
+
+ for (ManipulationUnit info : m_manipulationUnits) {
+
+ byte[] bytecode;
+ try {
+ bytecode = m_store.read(info.getResourcePath());
+ } catch (IOException e) {
+ m_reporter.error("Cannot find bytecode for class '" + info.getClassName() + "': no bytecode found.");
+ return;
+ }
+
+ // Is the visitor interested in this component ?
+ ManipulationResultVisitor result = m_manipulationVisitor.visitManipulationResult(info.getComponentMetadata());
+
+ if (result != null) {
+ // Should always be the case
+
+ // Manipulation preparation
+ Manipulator manipulator = new Manipulator(m_classLoader);
+ try {
+ manipulator.prepare(bytecode);
+ } catch (IOException e) {
+ m_reporter.error("Cannot analyze the class " + info.getClassName() + " : " + e.getMessage());
+ return;
+ }
+
+ // Inner class preparation
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ String outerClassInternalName = info.getClassName().replace('.', '/');
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = m_store.read(resourcePath);
+ manipulator.prepareInnerClass(inner, innerClassBytecode);
+ } catch (IOException e) {
+ m_reporter.error("Cannot find or analyze inner class '" + resourcePath + "'");
+ return;
+ }
+ }
+
+ // Now manipulate the classes.
+ try {
+ byte[] out = manipulator.manipulate(bytecode);
+ // Call the visitor
+ result.visitManipulatedResource(info.getResourcePath(), out);
+ } catch (IOException e) {
+ m_reporter.error("Cannot manipulate the class " + info.getClassName() + " : " + e.getMessage());
+ return;
+ }
+
+ // Visit inner classes
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ String outerClassInternalName = info.getClassName().replace('.', '/');
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = m_store.read(resourcePath);
+ } catch (IOException e) {
+ m_reporter.error("Cannot find inner class '" + resourcePath + "'");
+ return;
+ }
+
+ // Manipulate inner class
+ // Notice that (for performance reason) re-use the class version information
+ // discovered in the main class instead of re-parsing the inner class to find
+ // its own class version
+ try {
+ byte[] manipulated = manipulator.manipulateInnerClass(inner, innerClassBytecode);
+ // Propagate manipulated resource
+ result.visitManipulatedResource(resourcePath, manipulated);
+ } catch (IOException e) {
+ m_reporter.error("Cannot manipulate inner class '" + resourcePath + "'");
+ return;
+ }
+ }
+
+ // Compute manipulation metadata
+ result.visitClassStructure(manipulator.getManipulationMetadata());
+
+ // All resources have been manipulated for this component
+ result.visitEnd();
+ }
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java
new file mode 100644
index 0000000..c186bd7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Visit manipulation results.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManipulationResultVisitor {
+
+ /**
+ * Called once per visitor with the class' structure discovered during manipulation.
+ * @param structure Component's structure (discovered during manipulation, not the data from metadata.xml)
+ */
+ void visitClassStructure(Element structure);
+
+ /**
+ * Accept a manipulated resource (main component class or inner classes).
+ * @param type type name
+ * @param resource manipulated bytecode
+ */
+ void visitManipulatedResource(String type, byte[] resource);
+
+ /**
+ * Called when all resources from this manipulation result have been processed.
+ */
+ void visitEnd();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
new file mode 100644
index 0000000..c5558b6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
@@ -0,0 +1,70 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Component Info.
+ * Represent a component type to be manipulated or already manipulated.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ManipulationUnit {
+
+ private Element m_componentMetadata;
+
+ private String m_resourcePath;
+
+ private String m_className;
+
+ /**
+ * Constructor.
+ * @param resourcePath class name
+ * @param meta component type metadata
+ */
+ public ManipulationUnit(String resourcePath, Element meta) {
+ m_resourcePath = resourcePath;
+ m_componentMetadata = meta;
+ m_className = Strings.asClassName(resourcePath);
+ }
+
+ /**
+ * @return Component Type metadata.
+ */
+ public Element getComponentMetadata() {
+ return m_componentMetadata;
+ }
+
+ /**
+ * @return Resource path
+ */
+ public String getResourcePath() {
+ return m_resourcePath;
+ }
+
+ /**
+ * @return Fully qualified class name
+ */
+ public String getClassName() {
+ return m_className;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java
new file mode 100644
index 0000000..6dcfd9e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Visit manipulation results.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManipulationVisitor {
+
+ /**
+ * Accept a manipulation result for the given component metadata.
+ * @param metadata component's metadata (from XML or annotations)
+ * @return a ManipulationResultVisitor if interested in theses manipulation results
+ */
+ ManipulationResultVisitor visitManipulationResult(Element metadata);
+
+ /**
+ * Visit metadata not associated with a component (ie no bytecode manipulation needed).
+ * @param metadata usually {@code instance}/{@code composite} metadata
+ */
+ void visitMetadata(Element metadata);
+
+ /**
+ * Called when all metadata have been processed.
+ */
+ void visitEnd();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java
new file mode 100644
index 0000000..66c7a00
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.manipulator;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code MetadataProvider} is responsible to provide iPOJO's metadata.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface MetadataProvider {
+
+ /**
+ * Gather all the metadata.
+ * @return a list of iPOJO metadata (never return null)
+ * @throws IOException if something wet wrong during gathering.
+ */
+ List<Element> getMetadatas() throws IOException;
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
new file mode 100644
index 0000000..445caf2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -0,0 +1,388 @@
+/*
+ * 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.manipulator;
+
+import org.apache.felix.ipojo.manipulator.manifest.FileManifestProvider;
+import org.apache.felix.ipojo.manipulator.metadata.*;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.reporter.SystemReporter;
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.provider.ServiceLoaderModuleProvider;
+import org.apache.felix.ipojo.manipulator.store.DirectoryResourceStore;
+import org.apache.felix.ipojo.manipulator.store.JarFileResourceStore;
+import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder;
+import org.apache.felix.ipojo.manipulator.store.mapper.WABResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Constants;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor;
+import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.xml.parser.SchemaResolver;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.jar.JarFile;
+
+/**
+ * Pojoization allows creating an iPOJO bundle from a "normal" bundle.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Pojoization {
+
+ /**
+ * Flag describing if we need or not compute annotations.
+ * By default, compute the annotations.
+ */
+ private boolean m_ignoreAnnotations;
+
+ /**
+ * Flag describing if we need or not use local XSD files
+ * (i.e. use the {@link SchemaResolver} or not).
+ * If <code>true</code> the local XSD are used (default to {@literal false}).
+ */
+ private boolean m_useLocalXSD = false;
+
+ /**
+ * Reporter for error reporting.
+ */
+ private final Reporter m_reporter;
+
+ private final ModuleProvider m_moduleProvider;
+
+ public Pojoization() {
+ this(new SystemReporter());
+ }
+
+ public Pojoization(ModuleProvider provider) {
+ this(new SystemReporter(), provider);
+ }
+
+ public Pojoization(Reporter reporter) {
+ this(reporter, new ServiceLoaderModuleProvider());
+ }
+
+ public Pojoization(Reporter reporter, final ModuleProvider moduleProvider) {
+ m_reporter = reporter;
+ m_moduleProvider = moduleProvider;
+ m_reporter.info("Apache Felix iPOJO Manipulator - " + Constants.getVersion());
+ }
+
+ /**
+ * Activates annotation processing.
+ */
+ public void disableAnnotationProcessing() {
+ m_ignoreAnnotations = true;
+ }
+
+ /**
+ * Activates the entity resolver loading
+ * XSD files from the classloader.
+ */
+ public void setUseLocalXSD() {
+ m_useLocalXSD = true;
+ }
+
+ /**
+ * @return all the errors (fatal) reported by the manipulation process.
+ */
+ public List<String> getErrors() {
+ // Simple delegation for backward compatibility
+ return m_reporter.getErrors();
+ }
+
+ /**
+ * @return all the warnings (non fatal) reported by the manipulation process.
+ */
+ public List<String> getWarnings() {
+ // Simple delegation for backward compatibility
+ return m_reporter.getWarnings();
+ }
+
+ /**
+ * Manipulates an input bundle.
+ * This method creates an iPOJO bundle based on the given metadata file.
+ * The original and final bundles must be different.
+ * <p/>
+ * This method does not use the classloader parameter, and use the classloader having loaded the
+ * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended.
+ *
+ * @param in the original bundle.
+ * @param out the final bundle.
+ * @param metadata the iPOJO metadata input stream.
+ * @deprecated
+ */
+ public void pojoization(File in, File out, InputStream metadata) {
+ pojoization(in, out, metadata, this.getClass().getClassLoader());
+ }
+
+ /**
+ * Manipulates an input bundle.
+ * This method creates an iPOJO bundle based on the given metadata file.
+ * The original and final bundles must be different.
+ *
+ * @param in the original bundle.
+ * @param out the final bundle.
+ * @param metadata the iPOJO metadata input stream.
+ * @param loader the classloader used to compute the bytecode frames.
+ */
+ public void pojoization(File in, File out, InputStream metadata, ClassLoader loader) {
+ StreamMetadataProvider provider = new StreamMetadataProvider(metadata, m_reporter);
+ provider.setValidateUsingLocalSchemas(m_useLocalXSD);
+
+ ResourceStore store;
+ try {
+ JarFile origin = new JarFile(in);
+ JarFileResourceStore jfrs = new JarFileResourceStore(origin, out);
+ jfrs.setClassLoader(loader);
+ if (in.getName().endsWith(".war")) {
+ // this is a war file, use the right mapper
+ jfrs.setResourceMapper(new WABResourceMapper());
+ }
+ jfrs.setManifest(origin.getManifest());
+ DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+ dmb.setMetadataRenderer(new MetadataRenderer());
+ jfrs.setManifestBuilder(dmb);
+ store = jfrs;
+ } catch (IOException e) {
+ m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+ return;
+ }
+
+ ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+ pojoization(store, provider, visitor, loader);
+ }
+
+ private ManipulationVisitor createDefaultVisitorChain(ResourceStore store) {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(m_reporter);
+ writer.setResourceStore(store);
+
+ CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer);
+ checkFieldConsistencyVisitor.setReporter(m_reporter);
+ return checkFieldConsistencyVisitor;
+ }
+
+ /**
+ * Manipulates an input bundle.
+ * This method creates an iPOJO bundle based on the given metadata file.
+ * The original and final bundles must be different.
+ * <p/>
+ * This method does not use the classloader parameter, and use the classloader having loaded the
+ * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended.
+ *
+ * @param in the original bundle.
+ * @param out the final bundle.
+ * @param metadataFile the iPOJO metadata file (XML).
+ * @deprecated
+ */
+ public void pojoization(File in, File out, File metadataFile) {
+ pojoization(in, out, metadataFile, this.getClass().getClassLoader());
+ }
+
+ /**
+ * Manipulates an input bundle.
+ * This method creates an iPOJO bundle based on the given metadata file.
+ * The original and final bundles must be different.
+ *
+ * @param in the original bundle.
+ * @param out the final bundle.
+ * @param metadataFile the iPOJO metadata file (XML).
+ * @param loader the classloader used to compute the bytecode frames.
+ */
+ public void pojoization(File in, File out, File metadataFile, ClassLoader loader) {
+ MetadataProvider provider = new EmptyMetadataProvider();
+ if (metadataFile != null) {
+ FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+ fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+ provider = fileMetadataProvider;
+ }
+
+ ResourceStore store;
+ try {
+ JarFile origin = new JarFile(in);
+ JarFileResourceStore jfrs = new JarFileResourceStore(origin, out);
+ jfrs.setClassLoader(loader);
+ if (in.getName().endsWith(".war")) {
+ // this is a war file, use the right mapper
+ jfrs.setResourceMapper(new WABResourceMapper());
+ }
+ jfrs.setManifest(origin.getManifest());
+ DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+ dmb.setMetadataRenderer(new MetadataRenderer());
+ jfrs.setManifestBuilder(dmb);
+ store = jfrs;
+ } catch (IOException e) {
+ m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+ return;
+ }
+
+ ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+ pojoization(store, provider, visitor, loader);
+ }
+
+ /**
+ * Manipulates an expanded bundles.
+ * Classes are in the specified directory.
+ * this method allows to update a customized manifest.
+ * <p/>
+ * This method does not use the classloader parameter, and use the classloader having loaded the
+ * {@link org.apache.felix.ipojo.manipulator.Pojoization} class. It's definitely not recommended.
+ *
+ * @param directory the directory containing classes
+ * @param metadataFile the metadata file
+ * @param manifestFile the manifest file. <code>null</code> to use directory/META-INF/MANIFEST.mf
+ * @deprecated
+ */
+ public void directoryPojoization(File directory, File metadataFile, File manifestFile) {
+ directoryPojoization(directory, metadataFile, manifestFile, this.getClass().getClassLoader());
+ }
+
+ /**
+ * Manipulates an expanded bundles.
+ * Classes are in the specified directory.
+ * this method allows to update a customized manifest.
+ *
+ * @param directory the directory containing classes
+ * @param metadataFile the metadata file
+ * @param manifestFile the manifest file. <code>null</code> to use directory/META-INF/MANIFEST.mf
+ * @param loader the classloader used to compute the bytecode frames.
+ */
+ public void directoryPojoization(File directory, File metadataFile, File manifestFile, ClassLoader loader) {
+ // Get the metadata.xml location if not null
+ MetadataProvider provider = new EmptyMetadataProvider();
+ if (metadataFile != null) {
+ FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+ fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+ provider = fileMetadataProvider;
+ }
+
+ ManifestProvider manifestProvider;
+ File selectedManifestFile;
+ if (manifestFile != null) {
+ if (manifestFile.isFile()) {
+ try {
+ manifestProvider = new FileManifestProvider(manifestFile);
+ selectedManifestFile = manifestFile;
+ } catch (IOException e) {
+ m_reporter.error("Cannot read Manifest from '" + manifestFile.getAbsolutePath() + "'");
+ return;
+ }
+ } else {
+ m_reporter.error("The manifest file " + manifestFile.getAbsolutePath() + " does not exist");
+ return;
+ }
+ } else {
+ // If the manifest is not specified, the m_dir/META-INF/MANIFEST.MF is used.
+ File metaInf = new File(directory, "META-INF");
+ File original = new File(metaInf, "MANIFEST.MF");
+ if (original.isFile()) {
+ try {
+ manifestProvider = new FileManifestProvider(original);
+ selectedManifestFile = original;
+ } catch (IOException e) {
+ m_reporter.error("Cannot read Manifest from '" + original.getAbsolutePath() + "'");
+ return;
+ }
+ } else {
+ m_reporter.error("The manifest file " + original.getAbsolutePath() + " does not exist");
+ return;
+ }
+ }
+
+ DirectoryResourceStore store;
+ if (directory.exists() && directory.isDirectory()) {
+ store = new DirectoryResourceStore(directory);
+ File webinf = new File(directory, "WEB-INF");
+ if (directory.getName().endsWith(".war") || webinf.isDirectory()) {
+ // this is a war file, use the right mapper
+ store.setResourceMapper(new WABResourceMapper());
+ }
+ store.setManifest(manifestProvider.getManifest());
+ store.setManifestFile(selectedManifestFile);
+ DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+ dmb.setMetadataRenderer(new MetadataRenderer());
+ store.setManifestBuilder(dmb);
+ } else {
+ m_reporter.error("The directory " + directory.getAbsolutePath() + " does not exist or is not a directory.");
+ return;
+ }
+
+ ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+ pojoization(store, provider, visitor, loader);
+
+ }
+
+ public void pojoization(final ResourceStore store,
+ final MetadataProvider metadata,
+ final ManipulationVisitor visitor,
+ final ClassLoader loader) {
+
+ ManipulationEngine engine = new ManipulationEngine(loader);
+ engine.setResourceStore(store);
+ engine.setReporter(m_reporter);
+ engine.setManipulationVisitor(visitor);
+
+ try {
+
+ // Creates a composite to store multiple metadata providers
+ CompositeMetadataProvider composite = new CompositeMetadataProvider(m_reporter);
+ composite.addMetadataProvider(metadata);
+
+ if (!m_ignoreAnnotations) {
+ composite.addMetadataProvider(new AnnotationMetadataProvider(store, m_moduleProvider, m_reporter));
+ }
+
+ // Get metadata
+ List<Element> metadatas = composite.getMetadatas();
+
+ // Construct ManipulationUnits
+ // And collect non-component metadata
+ for (Element meta : metadatas) {
+ String name = Metadatas.getComponentType(meta);
+ if (name != null) {
+ // Only handler and component have a classname attribute
+ String path = Strings.asResourcePath(name);
+ engine.addManipulationUnit(new ManipulationUnit(path, meta));
+ } else {
+ visitor.visitMetadata(meta);
+ }
+ }
+
+ } catch (IOException e) {
+ m_reporter.error("Cannot load metadata " + e.getMessage());
+ return;
+ }
+
+ // Start the manipulation
+ engine.generate();
+
+ // Tell the visitor that we have finished
+ visitor.visitEnd();
+
+ }
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
new file mode 100644
index 0000000..ba221d3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
@@ -0,0 +1,200 @@
+/*
+ * 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.manipulator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parse on OSGi Manifest clause.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class QuotedTokenizer {
+ /**
+ * String to parse.
+ */
+ String m_string;
+
+ /**
+ * Index.
+ */
+ int m_index = 0;
+
+ /**
+ * Default separator to use.
+ */
+ String m_separators;
+
+ /**
+ * Does the tokenizer returns token.
+ */
+ boolean m_returnTokens;
+
+ /**
+ * Peek.
+ */
+ String m_peek;
+
+ /**
+ * Separator.
+ */
+ char m_separator;
+
+ /**
+ * Constructors.
+ * @param string : input String.
+ * @param separators : separators.
+ * @param returnTokens : should the tokenizer return tokens ?
+ */
+ public QuotedTokenizer(String string, String separators, boolean returnTokens) {
+ if (string == null) {
+ throw new IllegalArgumentException("string argument must be not null");
+ }
+ this.m_string = string;
+ this.m_separators = separators;
+ this.m_returnTokens = returnTokens;
+ }
+
+ /**
+ * Constructors.
+ * Set returnTokens to false.
+ * @param string : input String.
+ * @param separators : separators
+ */
+ public QuotedTokenizer(String string, String separators) {
+ this(string, separators, false);
+ }
+
+ /**
+ * Get the next token.
+ * @param separators : separators to used.
+ * @return : the next token.
+ */
+ public String nextToken(String separators) {
+ m_separator = 0;
+ if (m_peek != null) {
+ String tmp = m_peek;
+ m_peek = null;
+ return tmp;
+ }
+
+ if (m_index == m_string.length()) { return null; }
+
+ StringBuffer sb = new StringBuffer();
+
+ while (m_index < m_string.length()) {
+ char c = m_string.charAt(m_index++);
+
+ if (Character.isWhitespace(c)) {
+ if (m_index == m_string.length()) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (separators.indexOf(c) >= 0) {
+ if (m_returnTokens) {
+ m_peek = Character.toString(c);
+ } else {
+ m_separator = c;
+ }
+ break;
+ }
+
+ switch (c) {
+ case '"':
+ case '\'':
+ quotedString(sb, c);
+ break;
+
+ default:
+ sb.append(c);
+ }
+ }
+ String result = sb.toString().trim();
+ if (result.length() == 0 && m_index == m_string.length()) { return null; }
+ return result;
+ }
+
+ /**
+ * Get the next token.
+ * Used the defined separators.
+ * @return the next token.
+ */
+ public String nextToken() {
+ return nextToken(m_separators);
+ }
+
+ /**
+ * Append the next quote to the given String Buffer.
+ * @param sb : accumulator.
+ * @param c : quote.
+ */
+ private void quotedString(StringBuffer sb, char c) {
+ char quote = c;
+ while (m_index < m_string.length()) {
+ c = m_string.charAt(m_index++);
+ if (c == quote) { break; }
+ if (c == '\\' && m_index < m_string.length() && m_string.charAt(m_index + 1) == quote) {
+ c = m_string.charAt(m_index++);
+ }
+ sb.append(c);
+ }
+ }
+
+ public String[] getTokens() {
+ return getTokens(0);
+ }
+
+ /**
+ * Get the list of tokens.
+ * @param cnt : array length.
+ * @return : the array of token.
+ */
+ private String[] getTokens(int cnt) {
+ String token = nextToken();
+ if (token == null) {
+ return new String[cnt];
+ }
+
+ String[] result = getTokens(cnt + 1);
+ result[cnt] = token;
+ return result;
+ }
+
+ public char getSeparator() {
+ return m_separator;
+ }
+
+ /**
+ * Get token list.
+ * @return the list of token.
+ */
+ public List<String> getTokenSet() {
+ List<String> list = new ArrayList<String>();
+ String token = nextToken();
+ while (token != null) {
+ list.add(token);
+ token = nextToken();
+ }
+ return list;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java
new file mode 100644
index 0000000..74cc79a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java
@@ -0,0 +1,74 @@
+/*
+ * 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.manipulator;
+
+import java.util.List;
+
+/**
+ * A {@code Reporter} is responsible to handle feedback from within the
+ * manipulation process in order to let API consumers deal with errors
+ * and warnings.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Reporter {
+
+ /**
+ * Add aa trace message
+ * It accepts a {@link Throwable} as last argument.
+ * @param message trace message.
+ * @param args message's argument
+ */
+ void trace(String message, Object... args);
+
+ /**
+ * Add an informative message
+ * It accepts a {@link Throwable} as last argument.
+ * @param message info message.
+ * @param args message's argument
+ */
+ void info(String message, Object... args);
+
+ /**
+ * Add a message in the warning list.
+ * It accepts a {@link Throwable} as last argument.
+ * @param message warning message.
+ * @param args message's argument
+ */
+ void warn(String message, Object... args);
+
+ /**
+ * Add a message in the error list.
+ * It accepts a {@link Throwable} as last argument.
+ * @param message error message.
+ * @param args message's argument
+ */
+ void error(String message, Object... args);
+
+ /**
+ * @return all the errors (fatal) reported by the manipulation process.
+ */
+ List<String> getErrors();
+
+ /**
+ * @return all the warnings (non fatal) reported by the manipulation process.
+ */
+ List<String> getWarnings();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
new file mode 100644
index 0000000..4ae5495
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
@@ -0,0 +1,76 @@
+/*
+ * 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.manipulator;
+
+import java.io.IOException;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Abstract input/output for the manipulation process.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceStore {
+
+ /**
+ * Return the bytecode of the given class name.
+ * @param path normalized resource path (format: {@literal org/objectweb/asm/Visitor.class})
+ * @return the byte array representing the given class
+ * @throws IOException if resource was not found
+ */
+ byte[] read(String path) throws IOException;
+
+ /**
+ * Browse all resources available in this store.
+ * @param visitor is called for each available resource
+ */
+ void accept(ResourceVisitor visitor);
+
+ /**
+ * Notify the store that resource will be written.
+ * @throws IOException if there was an error
+ */
+ void open() throws IOException;
+
+ /**
+ * Writes the given Element into this store.
+ * Typically a store implementation will use this to build a Manifest.
+ * @param metadata Element metadata to be inserted
+ */
+ void writeMetadata(Element metadata);
+
+ /**
+ * Notify the builder that a new resource has been built and should
+ * be stored in the resulting bundle.
+ * @param resourcePath resource name of the class (format: {@literal org/objectweb/asm/Visitor.class})
+ * @param resource content of the resource
+ * @throws IOException if there was an error storing the resource
+ */
+ void write(String resourcePath, byte[] resource) throws IOException;
+
+ /**
+ * Close the store: no methods will be called anymore on this instance.
+ * @throws IOException if close failed
+ */
+ void close() throws IOException;
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java
new file mode 100644
index 0000000..d94c665
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.manipulator;
+
+/**
+ * A {@code ResourceVisitor} is invoked when a potential class is
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceVisitor {
+
+ /**
+ * Visit a resource discovered in the original bundle.
+ * @param name resource's name (format: {@literal org/objectweb/asm/Visitor.class})
+ */
+ void visit(String name);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java
new file mode 100644
index 0000000..8468124
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java
@@ -0,0 +1,49 @@
+/*
+ * 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.manipulator.manifest;
+
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ManifestProvider;
+
+/**
+ * A {@code DirectManifestProvider} simply serves an already available {@link Manifest}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DirectManifestProvider implements ManifestProvider {
+
+ /**
+ * Served Manifest.
+ */
+ private Manifest m_manifest;
+
+ /**
+ * Construct a provider servicing the given manifest.
+ * @param manifest Manifest to be serviced
+ */
+ public DirectManifestProvider(Manifest manifest) {
+ m_manifest = manifest;
+ }
+
+ public Manifest getManifest() {
+ return m_manifest;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java
new file mode 100644
index 0000000..23d441e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.manipulator.manifest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ManifestProvider;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+
+/**
+ * A {@code FileManifestProvider} reads a {@link Manifest} from the given input {@link File}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileManifestProvider implements ManifestProvider {
+
+ /**
+ * Read manifest.
+ */
+ private Manifest m_manifest;
+
+ /**
+ * Read the manifest from the given input file
+ * @param resource File pointing to a Manifest file
+ * @throws IOException if there is an error during File IO operations
+ * or if the file is not a valid manifest.
+ */
+ public FileManifestProvider(File resource) throws IOException {
+ m_manifest = new Manifest();
+ InputStream is = null;
+ try {
+ is = new FileInputStream(resource);
+ m_manifest.read(is);
+ } finally {
+ Streams.close(is);
+ }
+ }
+
+ public Manifest getManifest() {
+ return m_manifest;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
new file mode 100644
index 0000000..218cf10
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
@@ -0,0 +1,126 @@
+/*
+ * 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.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ClassMetadataCollector;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.manipulator.spi.provider.CoreModuleProvider;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.ClassReader;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Bindings.newBindingRegistry;
+
+/**
+ * A {@code AnnotationMetadataProvider} loads iPOJO metadata from bytecode of classes.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AnnotationMetadataProvider implements MetadataProvider {
+
+ private ResourceStore m_store;
+
+ private Reporter m_reporter;
+ private BindingRegistry m_registry;
+
+ public AnnotationMetadataProvider(final ResourceStore store,
+ final Reporter reporter) {
+ this(store, new CoreModuleProvider(), reporter);
+ }
+
+ public AnnotationMetadataProvider(final ResourceStore store,
+ final ModuleProvider provider,
+ final Reporter reporter) {
+ this(store, newBindingRegistry(reporter, store, provider), reporter);
+ }
+
+ public AnnotationMetadataProvider(final ResourceStore store,
+ final BindingRegistry registry,
+ final Reporter reporter) {
+ this.m_store = store;
+ this.m_registry = registry;
+ this.m_reporter = reporter;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+
+ final List<Element> metadata = new ArrayList<Element>();
+
+
+ m_store.accept(new ResourceVisitor() {
+ public void visit(String name) {
+ if (name.endsWith(".class")) {
+
+ // Read file's content
+ byte[] data = null;
+ try {
+ data = m_store.read(name);
+ } catch (IOException e) {
+ m_reporter.warn("Cannot read content of %s", name);
+ }
+
+ // We check the array size to avoid manipulating empty files
+ // produced by incremental compilers (like Eclipse Compiler)
+ if (data != null && data.length > 0) {
+ computeAnnotations(name, data, metadata);
+ } else {
+ m_reporter.error("Cannot compute annotations from %s : Empty file", name);
+ }
+ }
+ }
+ });
+
+ return metadata;
+ }
+
+ /**
+ * Parse the content of the class to detect annotated classes.
+ * @param name Resource's name
+ * @param bytecode the class' content to inspect.
+ * @param metadata list of metadata to be filled
+ */
+ private void computeAnnotations(String name, byte[] bytecode, List<Element> metadata) {
+
+ ClassReader cr = new ClassReader(bytecode);
+ ClassMetadataCollector collector = new ClassMetadataCollector(m_registry, m_reporter);
+ cr.accept(collector, 0);
+
+ if (collector.getComponentMetadata() != null) {
+ metadata.add(collector.getComponentMetadata());
+
+ // Instantiate ?
+ Element instance = collector.getInstanceMetadata();
+ if (instance != null) {
+ m_reporter.trace("Declaring an instance of %s", instance.getAttribute("component"));
+ metadata.add(instance);
+ }
+ }
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java
new file mode 100644
index 0000000..50416b3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java
@@ -0,0 +1,62 @@
+/*
+ * 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.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code CacheableMetadataProvider} provides simple caching methods to avoid
+ * calling {@link MetadataProvider#getMetadatas()} twice.
+ *
+ * TODO Do we really need this ? ATM it is not used ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CacheableMetadataProvider implements MetadataProvider {
+
+ /**
+ * Delegate.
+ */
+ private MetadataProvider m_delegate;
+
+ /**
+ * Cached elements.
+ */
+ private List<Element> m_cached;
+
+ public CacheableMetadataProvider(MetadataProvider delegate) {
+ m_delegate = delegate;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+
+ // Only ask the delegate if cache is empty
+ if (m_cached == null) {
+ m_cached = new ArrayList<Element>();
+ m_cached.addAll(m_delegate.getMetadatas());
+ }
+ return m_cached;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java
new file mode 100644
index 0000000..6196837
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java
@@ -0,0 +1,99 @@
+/*
+ * 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.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code CompositeMetadataProvider} is responsible to detect duplicates
+ * component's declaration.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeMetadataProvider implements MetadataProvider {
+
+ private List<MetadataProvider> m_providers = new ArrayList<MetadataProvider>();
+ private Reporter m_reporter;
+
+ public CompositeMetadataProvider(Reporter reporter) {
+ m_reporter = reporter;
+ }
+
+ public void addMetadataProvider(MetadataProvider provider) {
+ m_providers.add(provider);
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+ List<Element> metadata = new ArrayList<Element>();
+ for (MetadataProvider provider : m_providers) {
+
+ List<Element> loaded = provider.getMetadatas();
+
+ // Analyze each newly loaded metadata
+ // And find duplicate component definition
+
+ for (Element meta : loaded) {
+ if (isInstance(meta)) {
+ // This is an instance, just add it to the list
+ metadata.add(meta);
+ } else {
+ // Handler or Component
+ // Finds duplicate (if any)
+ String name = getComponentName(meta);
+ if (name != null) {
+ if (isDuplicate(metadata, name)) {
+ // TODO Try to add more information here, but what ?
+ m_reporter.warn("The component type " + name + " is duplicated.");
+ } else {
+ metadata.add(meta);
+ }
+ } else {
+ // no name, strange, but add it to the list
+ metadata.add(meta);
+ }
+ }
+ }
+ }
+ return metadata;
+ }
+
+ private boolean isDuplicate(List<Element> elements, String name) {
+ for (Element element : elements) {
+ if (!isInstance(element) && name.equals(getComponentName(element))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String getComponentName(Element element) {
+ return element.getAttribute("name");
+ }
+
+ private boolean isInstance(Element element) {
+ return "instance".equals(element.getName());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java
new file mode 100644
index 0000000..2fa1acf
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code EmptyMetadataProvider} simply returns an empty list of Element.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EmptyMetadataProvider implements MetadataProvider {
+
+ public List<Element> getMetadatas() throws IOException {
+ // Do not use Collections.emptyList() as the manipulator
+ // adds discovered components in this list
+ // TODO maybe the manipulator can have it's own list add we simply addAll() ?
+ return new ArrayList<Element>();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java
new file mode 100644
index 0000000..18d851b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java
@@ -0,0 +1,109 @@
+/*
+ * 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.manipulator.metadata;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code FileMetadataProvider} is responsible of loading all the {@literal .xml} files in the given directory.
+ * It also accepts a direct reference to a {@literal metadata.xml} file.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileMetadataProvider implements MetadataProvider {
+
+ /**
+ * Metadata source (file or directory).
+ */
+ private File m_source;
+
+ /**
+ * Feedback reporter.
+ */
+ private Reporter m_reporter;
+
+ /**
+ * Validate using local schemas or not ?
+ */
+ private boolean m_validateUsingLocalSchemas = false;
+
+ /**
+ * Constructs a metadata provider using the given source File (directory
+ * or file) to load iPOJO metadata.
+ * @param source source of the metadata
+ * @param reporter feedback reporter
+ */
+ public FileMetadataProvider(File source, Reporter reporter) {
+ m_source = source;
+ m_reporter = reporter;
+ }
+
+ public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+ m_validateUsingLocalSchemas = validateUsingLocalSchemas;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+
+ List<Element> metadata = new ArrayList<Element>();
+ traverse(m_source, metadata);
+ return metadata;
+ }
+
+ private void traverse(File file, List<Element> metadata) {
+ if (file.isDirectory()) {
+ // Traverse the directory and parse all files.
+ File[] files = file.listFiles();
+ for (File child : files) {
+ traverse(child, metadata);
+ }
+ } else if (file.getName().endsWith(".xml")) { // Detect XML by extension,
+ // others are ignored.
+ loadFileMetadata(file, metadata);
+ }
+
+ }
+
+ private void loadFileMetadata(File file, List<Element> metadata) {
+ try {
+ // Sanity check, should be OK, but we never know ...
+ InputStream stream = null;
+ URL url = file.toURI().toURL();
+ stream = url.openStream();
+ StreamMetadataProvider provider = new StreamMetadataProvider(stream, m_reporter);
+ provider.setValidateUsingLocalSchemas(m_validateUsingLocalSchemas);
+ metadata.addAll(provider.getMetadatas());
+ } catch (MalformedURLException e) {
+ m_reporter.error("Cannot open the metadata input stream from " + m_source.getAbsolutePath() + ": " + e.getMessage());
+ } catch (IOException e) {
+ m_reporter.error("Cannot open the metadata input stream: " + m_source.getAbsolutePath() + ": " + e.getMessage());
+ }
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java
new file mode 100644
index 0000000..034257e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java
@@ -0,0 +1,113 @@
+/*
+ * 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.manipulator.metadata;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.xml.parser.ParseException;
+import org.apache.felix.ipojo.xml.parser.SchemaResolver;
+import org.apache.felix.ipojo.xml.parser.XMLMetadataParser;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * A {@code StreamManifestProvider} knows how to load metadata from an InputStream.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StreamMetadataProvider implements MetadataProvider {
+
+ private InputStream m_stream;
+
+ private Reporter m_reporter;
+
+ private boolean m_validateUsingLocalSchemas = false;
+
+ public StreamMetadataProvider(InputStream stream, Reporter reporter) {
+ m_stream = stream;
+ m_reporter = reporter;
+ }
+
+ /**
+ * Force XML schemas resolution to be performed locally
+ */
+ public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+ m_validateUsingLocalSchemas = validateUsingLocalSchemas;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+
+ // First time we've been called: parse the XML Stream
+ List<Element> metadata = new ArrayList<Element>();
+
+ try {
+ XMLMetadataParser handler = new XMLMetadataParser();
+
+ XMLReader parser = XMLReaderFactory.createXMLReader();
+ parser.setContentHandler(handler);
+ parser.setFeature("http://xml.org/sax/features/validation", true);
+ parser.setFeature("http://apache.org/xml/features/validation/schema", true);
+ parser.setErrorHandler(handler);
+ if (m_validateUsingLocalSchemas) {
+ parser.setEntityResolver(new SchemaResolver());
+ }
+
+ // Parse the XML
+ InputSource is = new InputSource(m_stream);
+ parser.parse(is);
+ Element[] meta = handler.getMetadata();
+
+ // Add parsed metadata
+ if (meta != null) {
+ metadata.addAll(Arrays.asList(meta));
+ }
+
+ // Output a warning message if no metadata was found
+ if (meta == null || meta.length == 0) {
+ m_reporter.warn("Neither component types, nor instances in the XML metadata");
+ }
+
+ } catch (IOException e) {
+ m_reporter.error("Cannot open the metadata input stream: " + e.getMessage());
+ } catch (ParseException e) {
+ m_reporter.error("Parsing error when parsing the XML file: " + e.getMessage());
+ } catch (SAXParseException e) {
+ m_reporter.error("Error during metadata parsing at line " + e.getLineNumber() + " : " + e.getMessage());
+ } catch (SAXException e) {
+ m_reporter.error("Parsing error when parsing (Sax Error) the XML file: " + e.getMessage());
+ } finally {
+ Streams.close(m_stream);
+ }
+
+ return metadata;
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java
new file mode 100644
index 0000000..7346049
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java
@@ -0,0 +1,196 @@
+/*
+ * 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.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.*;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ClassMetadataCollector extends ClassVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * Output information.
+ */
+ private Reporter reporter;
+
+ /**
+ * Workbench where produced Elements will be merged and hierarchically organized.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Class currently being analyzed.
+ */
+ private ClassNode node;
+
+ private Element componentMetadata;
+
+ private Element instanceMetadata;
+
+ public ClassMetadataCollector(BindingRegistry registry, Reporter reporter) {
+ super(Opcodes.ASM5);
+ this.registry = registry;
+ this.reporter = reporter;
+ node = new ClassNode();
+ }
+
+ /**
+ * Build metadata. May be {@literal null} if no "component type" was found.
+ *
+ * @return Build metadata. May be {@literal null} if no "component type" was found.
+ */
+ public Element getComponentMetadata() {
+ return componentMetadata;
+ }
+
+ /**
+ * Build instance metadata. May be {@literal null} if no "component type" was found.
+ *
+ * @return Build metadata. May be {@literal null} if no "component type" was found.
+ */
+ public Element getInstanceMetadata() {
+ return instanceMetadata;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ node.visit(version, access, name, signature, superName, interfaces);
+ workbench = new ComponentWorkbench(registry, node);
+ }
+
+ /**
+ * Visit class annotations.
+ * This method detects @component and @provides annotations.
+ *
+ * @param desc : annotation descriptor.
+ * @param visible : is the annotation visible at runtime.
+ * @return the annotation visitor.
+ * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ //TODO we should find a better way to do this.
+ // Cannot retrieve the class object as @Configuration is in iPOJO runtime.
+ if (Type.getType(desc).getClassName().equals("org.apache.felix.ipojo.configuration.Configuration")) {
+ workbench.ignore(true);
+ return null;
+ }
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .type(this, node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+ /**
+ * Visit a field.
+ * Call the field collector visitor.
+ *
+ * @param access : field access.
+ * @param name : field name
+ * @param desc : field descriptor
+ * @param signature : field signature
+ * @param value : field value (static field only)
+ * @return the field visitor.
+ * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.Object)
+ */
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ return new FieldMetadataCollector(workbench, new FieldNode(access, name, desc, signature, value));
+ }
+
+ /**
+ * Visit a method.
+ * Call the method collector visitor.
+ *
+ * @param access : method access
+ * @param name : method name
+ * @param desc : method descriptor
+ * @param signature : method signature
+ * @param exceptions : method exceptions
+ * @return the Method Visitor.
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return new MethodMetadataCollector(workbench, new MethodNode(access, name, desc, signature, exceptions), reporter);
+ }
+
+ /**
+ * End of the visit : compute final elements.
+ *
+ * @see org.objectweb.asm.ClassVisitor#visitEnd()
+ */
+ @Override
+ public void visitEnd() {
+ // Only process real class (no annotations, no interfaces)
+ if (!(is(Opcodes.ACC_ANNOTATION) || is(Opcodes.ACC_INTERFACE) || is(Opcodes.ACC_ABSTRACT))) {
+ if (workbench.getRoot() == null) {
+ // No 'top-level' element has been contributed
+
+ if (workbench.ignore()) {
+ // Ignore this class.
+ return;
+ }
+
+ if (!workbench.getElements().isEmpty()) {
+ // There are other annotation's contribution on this type (additional handler declaration/configuration)
+ // That means that there is a missing 'component type' annotation
+
+ reporter.warn("Class %s has not been marked as a component type (no @Component, @Handler, " +
+ "...). It will be ignored by the iPOJO manipulator.",
+ workbench.getType().getClassName()
+ );
+ return;
+ } // else: no root and no elements
+ return;
+ }
+
+ componentMetadata = workbench.build();
+ instanceMetadata = workbench.getInstance();
+
+ // If we have an instance declared and the component metadata has a name, we update the component's attribute
+ // of the instance (https://issues.apache.org/jira/browse/FELIX-4052).
+ if (componentMetadata != null && componentMetadata.containsAttribute("name") && instanceMetadata != null) {
+ // Update the component attribute
+ instanceMetadata.addAttribute(new Attribute("component", componentMetadata.getAttribute("name")));
+ }
+
+ }
+ }
+
+ private boolean is(int flags) {
+ return (node.access & flags) == flags;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java
new file mode 100644
index 0000000..421bbba
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java
@@ -0,0 +1,176 @@
+/*
+ * 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.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentWorkbench {
+
+ /**
+ * Root element (usually <component /> or <handler/>).
+ * Maybe null until set.
+ */
+ private Element root;
+
+ /**
+ * Instance element (may be {@literal null}).
+ */
+ private Element instance;
+
+ /**
+ * Map of [element ids, element].
+ * This map is used to easily get an already created element.
+ */
+ private Map<String, Element> m_ids = new TreeMap<String, Element>();
+
+ /**
+ * Map of [element, referto].
+ * This map is used to recreate the element hierarchy.
+ * Stored element are added under referred element.
+ */
+ private Map<Element, String> m_elements = new LinkedHashMap<Element, String>();
+
+ private Type type;
+
+ private BindingRegistry bindingRegistry;
+
+ private ClassNode classNode;
+
+ /**
+ * A flag indicating if the class needs to be ignored.
+ */
+ private boolean toIgnore;
+
+ public ComponentWorkbench(BindingRegistry bindingRegistry, ClassNode node) {
+ this.bindingRegistry = bindingRegistry;
+ this.classNode = node;
+ this.type = Type.getObjectType(node.name);
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public BindingRegistry getBindingRegistry() {
+ return bindingRegistry;
+ }
+
+ public ClassNode getClassNode() {
+ return classNode;
+ }
+
+ /**
+ * The identified root Element. May be null if at the visit time, the root as not been identified.
+ *
+ * @return the root Element. or {@literal null} if not defined at the execution time.
+ */
+ public Element getRoot() {
+ return root;
+ }
+
+ public void setRoot(Element root) {
+ // TODO check if root already assigned
+ this.root = root;
+ }
+
+ public Element getInstance() {
+ return instance;
+ }
+
+ public void setInstance(Element instance) {
+ this.instance = instance;
+ }
+
+ public Map<String, Element> getIds() {
+ return m_ids;
+ }
+
+ public Map<Element, String> getElements() {
+ return m_elements;
+ }
+
+ public Element build() {
+
+ if (root == null) {
+ // No 'top level' component Element has been registered
+ return null;
+ }
+
+ // Iterates on all contributed Elements
+ for (Element current : m_elements.keySet()) {
+
+ // If the traversed Element has a reference to another Element,
+ // it has to be moved inside that referenced Element
+ // This is useful for contributing data to other handlers
+
+ String refId = m_elements.get(current);
+ if (refId == null) {
+ // No reference provided, just add it a a direct child
+ root.addElement(current);
+ } else {
+
+ // Get the referenced Element (if any)
+ Element ref = m_ids.get(refId);
+ if (ref == null) {
+ // Add to the root Element
+ root.addElement(current);
+ } else {
+ // Add as child of the referenced Element
+ ref.addElement(current);
+ }
+ }
+ }
+
+ // Clear
+ m_ids.clear();
+ m_elements.clear();
+
+ return root;
+
+ }
+
+ /**
+ * Checks whether this class must be ignored.
+ *
+ * @return {@code true} if the class is ignored.
+ */
+ public boolean ignore() {
+ return toIgnore;
+ }
+
+ /**
+ * Sets the 'ignore' aspect of the current class.
+ *
+ * @param ignore whether or not the class must be ignored.
+ */
+ public void ignore(boolean ignore) {
+ this.toIgnore = ignore;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java
new file mode 100644
index 0000000..638f778
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java
@@ -0,0 +1,73 @@
+/*
+ * 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.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.FieldNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadataCollector extends FieldVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * The workbench currently in use.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Visited field.
+ */
+ private FieldNode node;
+
+ public FieldMetadataCollector(ComponentWorkbench workbench, FieldNode node) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.node = node;
+ this.registry = workbench.getBindingRegistry();
+ }
+
+ /**
+ * Visit annotations on the current field.
+ * @param desc : annotation name
+ * @param visible : is the annotation a runtime annotation.
+ * @return the annotation visitor visiting the annotation
+ * @see org.objectweb.asm.FieldVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .field(this, node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.java
new file mode 100644
index 0000000..556ba2a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.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.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadataCollector extends MethodVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * The workbench currently in use.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Visited field.
+ */
+ private MethodNode node;
+
+ public MethodMetadataCollector(ComponentWorkbench workbench, MethodNode node, Reporter reporter) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.node = node;
+ this.registry = workbench.getBindingRegistry();
+ }
+
+ /**
+ * Visit method annotations.
+ *
+ * @param desc : annotation name.
+ * @param visible : is the annotation visible at runtime.
+ * @return the visitor paring the visited annotation.
+ * @see org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .method(this, node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+ /**
+ * Visit a parameter annotation.
+ *
+ * @see org.objectweb.asm.MethodVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitParameterAnnotation(int index,
+ String desc,
+ boolean visible) {
+ // Only process annotations on constructor
+ if (node.name.equals("<init>")) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .parameter(this, node, index)
+ .annotatedWith(desc)
+ .get();
+
+ }
+ return super.visitParameterAnnotation(index, desc, visible);
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationDiscovery.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationDiscovery.java
new file mode 100644
index 0000000..9a533b6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationDiscovery.java
@@ -0,0 +1,31 @@
+/*
+ * 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.manipulator.metadata.annotation.model;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 14:42
+ */
+public interface AnnotationDiscovery {
+ AnnotationVisitor visitAnnotation(String desc);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationType.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationType.java
new file mode 100644
index 0000000..4fcbd73
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/AnnotationType.java
@@ -0,0 +1,54 @@
+/*
+ * 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.manipulator.metadata.annotation.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 27/06/13
+ * Time: 13:37
+ */
+public class AnnotationType {
+ private final Type type;
+ private final List<Playback> m_playbacks = new ArrayList<Playback>();
+
+ public AnnotationType(final Type type) {
+ this.type = type;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public List<Playback> getPlaybacks() {
+ return m_playbacks;
+ }
+
+ public void traverse(AnnotationDiscovery visitor) {
+ for (Playback playback : m_playbacks) {
+ playback.accept(visitor);
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/Playback.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/Playback.java
new file mode 100644
index 0000000..12802f0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/Playback.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata.annotation.model;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * User: guillaume
+ * Date: 08/07/13
+ * Time: 16:30
+ */
+public interface Playback {
+ void accept(FieldVisitor visitor);
+
+ void accept(ClassVisitor visitor);
+
+ void accept(MethodVisitor visitor);
+
+ void accept(MethodVisitor visitor, int index);
+
+ void accept(AnnotationDiscovery visitor);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/ChainedAnnotationDiscovery.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/ChainedAnnotationDiscovery.java
new file mode 100644
index 0000000..caea0b1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/ChainedAnnotationDiscovery.java
@@ -0,0 +1,57 @@
+/*
+ * 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.manipulator.metadata.annotation.model.discovery;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.apache.felix.ipojo.manipulator.util.ChainedAnnotationVisitor;
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * User: guillaume
+ * Date: 10/07/13
+ * Time: 10:48
+ */
+public class ChainedAnnotationDiscovery implements AnnotationDiscovery {
+
+ private List<AnnotationDiscovery> m_discoveries = new ArrayList<AnnotationDiscovery>();
+
+ public List<AnnotationDiscovery> getDiscoveries() {
+ return m_discoveries;
+ }
+
+ public AnnotationVisitor visitAnnotation(final String desc) {
+ ChainedAnnotationVisitor chain = null;
+ for (AnnotationDiscovery discovery : m_discoveries) {
+ AnnotationVisitor visitor = discovery.visitAnnotation(desc);
+ if (visitor != null) {
+ if (chain == null) {
+ chain = new ChainedAnnotationVisitor();
+ }
+ chain.getVisitors().add(visitor);
+ }
+ }
+ return chain;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/HandlerBindingDiscovery.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/HandlerBindingDiscovery.java
new file mode 100644
index 0000000..7c2249f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/HandlerBindingDiscovery.java
@@ -0,0 +1,76 @@
+/*
+ * 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.manipulator.metadata.annotation.model.discovery;
+
+import org.apache.felix.ipojo.annotations.HandlerBinding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * The annotation visitor responsible for parsing the {@link org.apache.felix.ipojo.annotations.HandlerBinding}
+ * annotation.
+ */
+public class HandlerBindingDiscovery extends AnnotationVisitor implements AnnotationDiscovery {
+
+ public static final String HANDLER_BINDING_DESCRIPTOR = Type.getType(HandlerBinding.class).getDescriptor();
+
+ private boolean m_handlerBinding = false;
+ private String m_value = null;
+ private String m_namespace = null;
+
+ /**
+ * Constructs a new {@link org.objectweb.asm.AnnotationVisitor}.
+ */
+ public HandlerBindingDiscovery() {
+ super(Opcodes.ASM5);
+ }
+
+ public AnnotationVisitor visitAnnotation(final String desc) {
+ if (HANDLER_BINDING_DESCRIPTOR.equals(desc)) {
+ m_handlerBinding = true;
+ return this;
+ }
+ return null;
+ }
+
+ @Override
+ public void visit(final String name, final Object value) {
+ if ("value".equals(name)) {
+ m_value = (String) value;
+ }
+ if ("namespace".equals(name)) {
+ m_namespace = (String) value;
+ }
+ }
+
+ public boolean isHandlerBinding() {
+ return m_handlerBinding;
+ }
+
+ public String getValue() {
+ return m_value;
+ }
+
+ public String getNamespace() {
+ return m_namespace;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/IgnoredDiscovery.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/IgnoredDiscovery.java
new file mode 100644
index 0000000..71c7cc0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/IgnoredDiscovery.java
@@ -0,0 +1,48 @@
+/*
+ * 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.manipulator.metadata.annotation.model.discovery;
+
+import org.apache.felix.ipojo.annotations.Ignore;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 14:52
+ */
+public class IgnoredDiscovery implements AnnotationDiscovery {
+
+ public static final String IGNORE_DESCRIPTOR = Type.getType(Ignore.class).getDescriptor();
+
+ private boolean m_ignore = false;
+
+ public AnnotationVisitor visitAnnotation(final String desc) {
+ if (IGNORE_DESCRIPTOR.equals(desc)) {
+ m_ignore = true;
+ }
+ return null;
+ }
+
+ public boolean isIgnore() {
+ return m_ignore;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/StereotypeDiscovery.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/StereotypeDiscovery.java
new file mode 100644
index 0000000..a8438da
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/discovery/StereotypeDiscovery.java
@@ -0,0 +1,48 @@
+/*
+ * 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.manipulator.metadata.annotation.model.discovery;
+
+import org.apache.felix.ipojo.annotations.Stereotype;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 14:52
+ */
+public class StereotypeDiscovery implements AnnotationDiscovery {
+
+ public static final String STEREOTYPE_DESCRIPTOR = Type.getType(Stereotype.class).getDescriptor();
+
+ private boolean m_stereotype = false;
+
+ public AnnotationVisitor visitAnnotation(final String desc) {
+ if (STEREOTYPE_DESCRIPTOR.equals(desc)) {
+ m_stereotype = true;
+ }
+ return null;
+ }
+
+ public boolean isStereotype() {
+ return m_stereotype;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlayback.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlayback.java
new file mode 100644
index 0000000..3b7a529
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlayback.java
@@ -0,0 +1,264 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal;
+
+import static java.lang.String.format;
+import static org.objectweb.asm.Type.getType;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 08/07/13
+ * Time: 17:15
+ */
+public class AnnotationPlayback implements Playback {
+
+ public static final List<? extends Class<? extends Serializable>> BOXED_TYPES = Arrays.asList(Byte.class, Long.class, Character.class, Boolean.class, Double.class, Float.class, Integer.class, Short.class);
+ private final Annotation m_annotation;
+ private final Type m_annotationType;
+
+ public AnnotationPlayback(final Annotation annotation) {
+ m_annotation = annotation;
+ m_annotationType = Type.getType(annotation.annotationType());
+ }
+
+ private Map<String, Object> getValues() {
+ Map<String, Object> values = new HashMap<String, Object>();
+ for (Method method : m_annotation.annotationType().getDeclaredMethods()) {
+ try {
+ values.put(method.getName(), method.invoke(m_annotation));
+ } catch (Throwable t) {
+ throw new IllegalStateException(
+ format("Cannot get value of the %s.%s attribute",
+ m_annotation.annotationType().getSimpleName(),
+ method.getName()),
+ t
+ );
+ }
+ }
+ return values;
+ }
+ public void accept(final FieldVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_annotationType.getDescriptor(),
+ true);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final ClassVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_annotationType.getDescriptor(),
+ true);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final MethodVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_annotationType.getDescriptor(),
+ true);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final MethodVisitor visitor, final int index) {
+ AnnotationVisitor av = visitor.visitParameterAnnotation(index,
+ m_annotationType.getDescriptor(),
+ true);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final AnnotationDiscovery visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_annotationType.getDescriptor());
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ private void accept(final AnnotationVisitor visitor) {
+ // As per the ASM doc, visit methods must be called in a given order:
+ // 1. visit()
+ // 2. visitEnum()
+ // 3. visitAnnotation()
+ // 4. visitArray()
+
+ // So values must be sorted
+ Map<String, Object> values = getValues();
+ accept(values, visitor);
+ acceptEnum(values, visitor);
+ acceptAnnotation(values, visitor);
+ acceptArray(values, visitor);
+
+ // Do not forget to visitEnd()
+ visitor.visitEnd();
+
+ // TODO This should disappear, only useful for testing
+ if (!values.isEmpty()) {
+ // We missed something during serialization
+ throw new IllegalStateException(
+ format("Attributes of @%s could not be serialized: %s",
+ m_annotation.annotationType().getSimpleName(),
+ values.keySet())
+ );
+ }
+ }
+
+ private void acceptAnnotation(final Map<String, Object> values, final AnnotationVisitor visitor) {
+ Map<String, Object> copy = new HashMap<String, Object>(values);
+ for (Map.Entry<String, Object> entry : copy.entrySet()) {
+
+ Class<?> type = entry.getValue().getClass();
+ if (Annotation.class.isAssignableFrom(type)) {
+
+ Annotation annotation = (Annotation) entry.getValue();
+ AnnotationVisitor annotationVisitor = visitor.visitAnnotation(entry.getKey(),
+ getType(annotation.annotationType()).getDescriptor());
+ if (annotationVisitor != null) {
+ AnnotationPlayback playback = new AnnotationPlayback(annotation);
+ playback.accept(annotationVisitor);
+ }
+
+ values.remove(entry.getKey());
+ }
+ }
+ }
+
+ private void acceptEnum(final Map<String, Object> values, final AnnotationVisitor visitor) {
+
+ Map<String, Object> copy = new HashMap<String, Object>(values);
+ for (Map.Entry<String, Object> entry : copy.entrySet()) {
+
+ Class<?> type = entry.getValue().getClass();
+ if (type.isEnum()) {
+ Enum<?> enumValue = (Enum<?>) entry.getValue();
+ visitor.visitEnum(entry.getKey(),
+ getType(type).getDescriptor(),
+ enumValue.name());
+
+ values.remove(entry.getKey());
+ }
+ }
+ }
+
+ private void accept(final Map<String, Object> values, final AnnotationVisitor visitor) {
+
+ Map<String, Object> copy = new HashMap<String, Object>(values);
+ for (Map.Entry<String, Object> entry : copy.entrySet()) {
+
+ Class<?> type = entry.getValue().getClass();
+ if (isSimpleType(type)) {
+
+ // Accept Byte, Boolean, Character, Short, Integer, Long, Float, Double
+ // Accept String
+ // Accept Array of byte, boolean, char, short, int, long, float, double
+ visitor.visit(entry.getKey(), transform(entry.getValue()));
+
+ values.remove(entry.getKey());
+ }
+ }
+ }
+
+ private boolean isSimpleType(final Class<?> type) {
+ return isPrimitive(type) ||
+ String.class.equals(type) ||
+ Class.class.equals(type) ||
+ (type.isArray() && isPrimitive(type.getComponentType()));
+ }
+
+ private boolean isPrimitive(final Class<?> type) {
+ if (type.isPrimitive()) {
+ return true;
+ }
+
+ if (BOXED_TYPES.contains(type)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void acceptArray(final Map<String, Object> values, final AnnotationVisitor visitor) {
+ Map<String, Object> copy = new HashMap<String, Object>(values);
+ for (Map.Entry<String, Object> entry : copy.entrySet()) {
+
+ Class<?> type = entry.getValue().getClass();
+ if (type.isArray()) {
+
+ // Simple arrays have been visited using AnnotationVisitor.visit(String, Object)
+
+ AnnotationVisitor arrayVisitor = visitor.visitArray(entry.getKey());
+ if (arrayVisitor != null) {
+ Object[] array = (Object[]) entry.getValue();
+ Class<?> componentType = array.getClass().getComponentType();
+ Type asmType = Type.getType(componentType);
+
+ if (componentType.isEnum()) {
+ for (Object o : array) {
+ Enum eValue = (Enum) o;
+ arrayVisitor.visitEnum(null, asmType.getDescriptor(), eValue.name());
+ }
+ } else if (componentType.isAnnotation()) {
+ for (Object o : array) {
+ Annotation annotation = (Annotation) o;
+ AnnotationVisitor annotationVisitor = arrayVisitor.visitAnnotation(null, asmType.getDescriptor());
+ if (annotationVisitor != null) {
+ AnnotationPlayback playback = new AnnotationPlayback(annotation);
+ playback.accept(annotationVisitor);
+ }
+ }
+ } else {
+ for (Object o : array) {
+ arrayVisitor.visit(null, transform(o));
+ }
+ }
+
+ arrayVisitor.visitEnd();
+ }
+
+ values.remove(entry.getKey());
+ }
+ }
+ }
+
+ private Object transform(final Object value) {
+ if (value instanceof Class) {
+ return getType((Class) value);
+ }
+ return value;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationParser.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationParser.java
new file mode 100644
index 0000000..fdb000d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationParser.java
@@ -0,0 +1,38 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.objectweb.asm.ClassReader;
+
+/**
+ * User: guillaume
+ * Date: 01/07/13
+ * Time: 15:49
+ */
+public class AnnotationParser {
+ public AnnotationType read(byte[] resource) {
+ ClassReader reader = new ClassReader(resource);
+ AnnotationTypeVisitor visitor = new AnnotationTypeVisitor();
+ reader.accept(visitor, ClassReader.SKIP_CODE);
+ return visitor.getAnnotationType();
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationTypeVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationTypeVisitor.java
new file mode 100644
index 0000000..e0b4e58
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/AnnotationTypeVisitor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.parser.replay.AnnotationVisitorPlayback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ *
+ */
+public class AnnotationTypeVisitor extends ClassVisitor {
+
+ private AnnotationType annotationType;
+
+ public AnnotationTypeVisitor() {
+ super(Opcodes.ASM5);
+ }
+
+ @Override
+ public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
+ annotationType = new AnnotationType(Type.getObjectType(name));
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
+ // Build annotations of this annotation type
+ AnnotationVisitorPlayback playback = new AnnotationVisitorPlayback(desc, visible);
+ annotationType.getPlaybacks().add(playback);
+ return playback;
+ }
+
+ public AnnotationType getAnnotationType() {
+ return annotationType;
+ }
+
+ // Note: if we override visitMethod here, we could get the annotation's default values.
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorder.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorder.java
new file mode 100644
index 0000000..cb0e812
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorder.java
@@ -0,0 +1,68 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Record annotation to be replayed later.
+ */
+public class AnnotationRecorder extends AnnotationVisitor implements Replay {
+
+ private List<Replay> m_replays = new ArrayList<Replay>();
+
+ public AnnotationRecorder() {
+ super(Opcodes.ASM5);
+ }
+
+ public void visit(final String name, final Object value) {
+ m_replays.add(new Visit(name, value));
+ }
+
+ public void visitEnum(final String name, final String desc, final String value) {
+ m_replays.add(new VisitEnum(name, desc, value));
+ }
+
+ public AnnotationVisitor visitAnnotation(final String name, final String desc) {
+ AnnotationRecorder sub = new AnnotationRecorder();
+ m_replays.add(new VisitAnnotation(name, desc, sub));
+ return sub;
+ }
+
+ public AnnotationVisitor visitArray(final String name) {
+ AnnotationRecorder sub = new AnnotationRecorder();
+ m_replays.add(new VisitArray(name, sub));
+ return sub;
+ }
+
+ public void visitEnd() {
+ m_replays.add(new VisitEnd());
+ }
+
+ public void accept(final AnnotationVisitor visitor) {
+ for (Replay replay : m_replays) {
+ replay.accept(visitor);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationVisitorPlayback.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationVisitorPlayback.java
new file mode 100644
index 0000000..95dd6eb
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationVisitorPlayback.java
@@ -0,0 +1,77 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * User: guillaume
+ * Date: 08/07/13
+ * Time: 16:07
+ */
+public class AnnotationVisitorPlayback extends AnnotationRecorder implements Playback {
+ private final String m_desc;
+ private final boolean m_visible;
+
+ public AnnotationVisitorPlayback(final String desc, final boolean visible) {
+ m_desc = desc;
+ m_visible = visible;
+ }
+
+ public void accept(final FieldVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_desc, m_visible);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final ClassVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_desc, m_visible);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final MethodVisitor visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_desc, m_visible);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final MethodVisitor visitor, int index) {
+ AnnotationVisitor av = visitor.visitParameterAnnotation(index, m_desc, m_visible);
+ if (av != null) {
+ accept(av);
+ }
+ }
+
+ public void accept(final AnnotationDiscovery visitor) {
+ AnnotationVisitor av = visitor.visitAnnotation(m_desc);
+ if (av != null) {
+ accept(av);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Replay.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Replay.java
new file mode 100644
index 0000000..1597936
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Replay.java
@@ -0,0 +1,31 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:23
+*/
+public interface Replay {
+ void accept(AnnotationVisitor visitor);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Visit.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Visit.java
new file mode 100644
index 0000000..4c3eff2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/Visit.java
@@ -0,0 +1,41 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:23
+*/
+public class Visit implements Replay {
+ private final String m_name;
+ private final Object m_value;
+
+ public Visit(final String name, final Object value) {
+ m_name = name;
+ m_value = value;
+ }
+
+ public void accept(AnnotationVisitor visitor) {
+ visitor.visit(m_name, m_value);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitAnnotation.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitAnnotation.java
new file mode 100644
index 0000000..59a30e5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitAnnotation.java
@@ -0,0 +1,46 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:24
+*/
+public class VisitAnnotation implements Replay {
+ private final String m_name;
+ private final String m_desc;
+ private final AnnotationRecorder m_sub;
+
+ public VisitAnnotation(final String name, final String desc, final AnnotationRecorder sub) {
+ m_name = name;
+ m_desc = desc;
+ m_sub = sub;
+ }
+
+ public void accept(final AnnotationVisitor visitor) {
+ AnnotationVisitor child = visitor.visitAnnotation(m_name, m_desc);
+ if (child != null) {
+ m_sub.accept(child);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitArray.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitArray.java
new file mode 100644
index 0000000..5a4149e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitArray.java
@@ -0,0 +1,44 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:24
+*/
+public class VisitArray implements Replay {
+ private final String m_name;
+ private final AnnotationRecorder m_sub;
+
+ public VisitArray(final String name, final AnnotationRecorder sub) {
+ m_name = name;
+ m_sub = sub;
+ }
+
+ public void accept(final AnnotationVisitor visitor) {
+ AnnotationVisitor child = visitor.visitArray(m_name);
+ if (child != null) {
+ m_sub.accept(child);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnd.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnd.java
new file mode 100644
index 0000000..2bdebd5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnd.java
@@ -0,0 +1,34 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:24
+*/
+public class VisitEnd implements Replay {
+
+ public void accept(final AnnotationVisitor visitor) {
+ visitor.visitEnd();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnum.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnum.java
new file mode 100644
index 0000000..ce044d2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/VisitEnum.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata.annotation.model.parser.replay;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 30/05/13
+* Time: 17:23
+*/
+public class VisitEnum implements Replay {
+ private final String m_name;
+ private final String m_desc;
+ private final String m_value;
+
+ public VisitEnum(final String name, final String desc, final String value) {m_name = name;
+ m_desc = desc;
+ m_value = value;
+ }
+
+ public void accept(final AnnotationVisitor visitor) {
+ visitor.visitEnum(m_name, m_desc, m_value);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java
new file mode 100644
index 0000000..caa45f4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java
@@ -0,0 +1,290 @@
+/*
+ * 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.manipulator.metadata.annotation.module;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.*;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.Action;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.MethodBindVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.ParameterBindVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.GenericVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.apache.felix.ipojo.manipulator.spi.AbsBindingModule;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.tree.MethodNode;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.lang.annotation.ElementType;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultBindingModule extends AbsBindingModule {
+
+ /**
+ * Configure all the iPOJO's default annotation's bindings.
+ */
+ public void configure() {
+
+ // Class level annotations
+ // --------------------------------
+ bind(Component.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ComponentVisitor(context.getWorkbench(), context.getReporter());
+ }
+ });
+
+ bind(Handler.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new HandlerVisitor(context.getWorkbench(), context.getReporter());
+ }
+ });
+
+ bind(Provides.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ProvidesVisitor(context.getWorkbench());
+ }
+ });
+
+
+ bind(HandlerDeclaration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Reporter reporter = context.getReporter();
+ return new HandlerDeclarationVisitor(context.getWorkbench(), getFreshDocumentBuilder(reporter), reporter);
+ }
+ });
+
+ bind(Instantiate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new InstantiateVisitor(context.getWorkbench());
+ }
+ });
+
+ // Field level annotations
+ // --------------------------------
+ bind(Requires.class)
+ .when(on(ElementType.FIELD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new RequiresVisitor(context.getWorkbench(), context.getFieldNode().name);
+ }
+ })
+ .when(on(ElementType.PARAMETER))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ParameterBindVisitor(context.getWorkbench(), Action.BIND, context.getParameterIndex());
+ }
+ });
+
+ bind(Controller.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ControllerVisitor(context.getWorkbench(), context.getFieldNode().name);
+ }
+ });
+
+ bind(ServiceProperty.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ String name = context.getFieldNode().name;
+ ComponentWorkbench workbench = context.getWorkbench();
+
+ if (!workbench.getIds().containsKey("provides")) {
+ // The provides annotation is already computed.
+ context.getReporter().warn("The component does not provide services, skip ServiceProperty for {}", name);
+ return null;
+ } else {
+ // Get the provides element
+ Element provides = workbench.getIds().get("provides");
+ return new FieldPropertyVisitor(name, provides);
+ }
+
+ }
+ });
+
+ bind(ServiceController.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ String name = context.getFieldNode().name;
+ ComponentWorkbench workbench = context.getWorkbench();
+
+ if (!workbench.getIds().containsKey("provides")) { // The provides annotation is already computed.
+ context.getReporter().warn("The component does not provide services, skip @ServiceController for {}", name);
+ return null;
+ } else {
+ // Get the provides element
+ Element provides = workbench.getIds().get("provides");
+ return new ServiceControllerVisitor(name, provides);
+ }
+
+ }
+ });
+
+ bind(Property.class)
+ .when(on(ElementType.FIELD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ Element properties = Elements.getPropertiesElement(workbench);
+ String name = context.getFieldNode().name;
+ return new FieldPropertyVisitor(name, properties);
+ }
+
+ })
+ .when(on(ElementType.METHOD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ // @Property on method parameter
+ Element properties = Elements.getPropertiesElement(workbench);
+ String name = context.getMethodNode().name;
+ return new MethodPropertyVisitor(properties, name);
+ }
+ })
+ .when(on(ElementType.PARAMETER))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ // @Property on method parameter
+ Element properties = Elements.getPropertiesElement(workbench);
+ MethodNode method = context.getMethodNode();
+ return new ParameterPropertyVisitor(properties, method, context.getParameterIndex());
+ }
+ });
+
+ bind(Validate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new LifecycleVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name),
+ LifecycleVisitor.Transition.VALIDATE);
+ }
+ });
+
+ bind(Invalidate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new LifecycleVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name),
+ LifecycleVisitor.Transition.INVALIDATE);
+ }
+ });
+
+ bind(Updated.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new UpdatedVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name));
+ }
+ });
+
+ bind(Bind.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.BIND, node, context.getReporter());
+ }
+ });
+
+ bind(Unbind.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.UNBIND, node, context.getReporter());
+ }
+ });
+
+ bind(Modified.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.MODIFIED, node, context.getReporter());
+ }
+ });
+
+ bind(PostRegistration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new PostRegistrationVisitor(context.getWorkbench(), node.name);
+ }
+ });
+
+ bind(PostUnregistration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = context.getMethodNode();
+ return new PostUnregistrationVisitor(context.getWorkbench(), node.name);
+ }
+ });
+
+ bind(Context.class).to(new GenericVisitorFactory("context", ""));
+ }
+
+ private DocumentBuilder m_builder;
+
+
+ /**
+ * Creates a 'fresh' document builder.
+ * @return a new document builder is not already created, else reset
+ * the created one, and return it.
+ */
+ protected DocumentBuilder getFreshDocumentBuilder(Reporter reporter) {
+ if (m_builder == null) {
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try {
+ m_builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ // TODO GSA is this acceptable to throw a RuntimeException here ?
+ reporter.warn("Cannot get a fresh DocumentBuilder", e);
+ }
+
+ return m_builder;
+ }
+
+ // The builder has to be reset
+ m_builder.reset();
+
+ return m_builder;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java
new file mode 100644
index 0000000..fc6a963
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java
@@ -0,0 +1,67 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static java.lang.String.format;
+
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.objectweb.asm.Type;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Triple storing the source annotation, the associated factory and the predicate for conditional support.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Binding {
+ private Type annotationType;
+ private AnnotationVisitorFactory factory;
+ private Predicate predicate;
+
+ public Type getAnnotationType() {
+ return annotationType;
+ }
+
+ public void setAnnotationType(Type annotationType) {
+ this.annotationType = annotationType;
+ }
+
+ public AnnotationVisitorFactory getFactory() {
+ return factory;
+ }
+
+ public void setFactory(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ }
+
+ public Predicate getPredicate() {
+ return predicate;
+ }
+
+ public void setPredicate(Predicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public String toString() {
+ return format("Binding[@%s->%s]", annotationType.getClassName(), factory);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java
new file mode 100644
index 0000000..0c80ce7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java
@@ -0,0 +1,43 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 16:12
+ */
+public interface BindingRegistry {
+ void addBindings(Iterable<Binding> bindings);
+
+ Selection selection(ComponentWorkbench workbench);
+
+ /**
+ * Find the list of {@link Binding} registered with the given annotation type.
+ * This method returns an empty List if no bindings are registered.
+ * @param descriptor denotes the annotation's type
+ * @return the list of {@link Binding} registered with the given descriptor, the list may be empty if no bindings are found.
+ */
+ List<Binding> getBindings(String descriptor);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistry.java
new file mode 100644
index 0000000..398db41
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistry.java
@@ -0,0 +1,62 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 16:09
+ */
+public abstract class CompletableBindingRegistry implements BindingRegistry {
+ private final BindingRegistry m_delegate;
+ private final Reporter m_reporter;
+
+ public CompletableBindingRegistry(final BindingRegistry delegate, final Reporter reporter) {
+ m_delegate = delegate;
+ m_reporter = reporter;
+ }
+
+ public List<Binding> getBindings(final String descriptor) {
+ List<Binding> bindings = m_delegate.getBindings(descriptor);
+ if (bindings.isEmpty()) {
+ List<Binding> ignored = createBindings(Type.getType(descriptor));
+ m_delegate.addBindings(ignored);
+ return ignored;
+ }
+ return bindings;
+ }
+
+ protected abstract List<Binding> createBindings(final Type type);
+
+ public void addBindings(final Iterable<Binding> bindings) {
+ m_delegate.addBindings(bindings);
+ }
+
+ public Selection selection(final ComponentWorkbench workbench) {
+ return new Selection(this, workbench, m_reporter);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistry.java
new file mode 100644
index 0000000..f76ec6a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistry.java
@@ -0,0 +1,79 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static java.util.Collections.emptyList;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.objectweb.asm.Type;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores all the {@link Binding}s coming from the {@link org.apache.felix.ipojo.manipulator.spi.Module}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultBindingRegistry implements BindingRegistry {
+ private final Map<String, List<Binding>> tree = new HashMap<String, List<Binding>>();
+ protected final Reporter reporter;
+
+ public DefaultBindingRegistry(Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ /**
+ * Stores the given Bindings
+ */
+ public void addBindings(Iterable<Binding> bindings) {
+ for (Binding binding : bindings) {
+ Type type = binding.getAnnotationType();
+
+ List<Binding> potential = tree.get(type.getDescriptor());
+ if (potential == null) {
+ // Annotation is not already found in supported list
+ potential = new ArrayList<Binding>();
+ tree.put(type.getDescriptor(), potential);
+ }
+
+ //reporter.trace("Registered @%s", type.getClassName());
+ potential.add(binding);
+ }
+ }
+
+ /**
+ * Initiate a {@link Selection} for the given workbench.
+ */
+ public Selection selection(ComponentWorkbench workbench) {
+ return new Selection(this, workbench, reporter);
+ }
+
+ public List<Binding> getBindings(String descriptor) {
+ List<Binding> bindings = tree.get(descriptor);
+ if (bindings == null) {
+ bindings = emptyList();
+ }
+ return bindings;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistry.java
new file mode 100644
index 0000000..ca84dcb
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistry.java
@@ -0,0 +1,46 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static java.util.Collections.singletonList;
+
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 16:09
+ */
+public class IgnoreAllBindingRegistry extends CompletableBindingRegistry {
+
+ public IgnoreAllBindingRegistry(final BindingRegistry delegate, final Reporter reporter) {
+ super(delegate, reporter);
+ }
+
+ @Override
+ protected List<Binding> createBindings(final Type type) {
+ return singletonList((Binding) new NullBinding(type));
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistry.java
new file mode 100644
index 0000000..0c7d59e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistry.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.manipulator.metadata.annotation.registry;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.FieldGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.MethodGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.ParameterGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.TypeGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.alwaysTrue;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 16:09
+ */
+public class LegacyGenericBindingRegistry extends CompletableBindingRegistry {
+ public static final Pattern CUSTOM_HANDLER_PATTERN = Pattern.compile("(.*\\.ipojo\\..*)|(.*\\.handler\\..*)");
+
+ public LegacyGenericBindingRegistry(final BindingRegistry delegate, final Reporter reporter) {
+ super(delegate, reporter);
+ }
+
+ @Override
+ protected List<Binding> createBindings(final Type type) {
+ if (CUSTOM_HANDLER_PATTERN.matcher(type.getClassName()).matches()) {
+ Binding binding = new Binding();
+ binding.setAnnotationType(type);
+ binding.setPredicate(alwaysTrue());
+ binding.setFactory(new AnnotationVisitorFactory() {
+ // Need to build a new Element instance for each created visitor
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ if (context.getClassNode() != null) {
+ return new TypeGenericVisitor(context.getWorkbench(),
+ Elements.buildElement(type));
+ } else if (context.getFieldNode() != null) {
+ return new FieldGenericVisitor(context.getWorkbench(),
+ Elements.buildElement(type),
+ context.getFieldNode());
+
+ } else if ((context.getMethodNode() != null) &&
+ (context.getParameterIndex() == BindingContext.NO_INDEX)) {
+ return new MethodGenericVisitor(context.getWorkbench(),
+ Elements.buildElement(type),
+ context.getMethodNode());
+ } else {
+ // last case: method parameter annotation
+ return new ParameterGenericVisitor(context.getWorkbench(),
+ Elements.buildElement(type),
+ context.getMethodNode(),
+ context.getParameterIndex());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "LegacyGenericVisitorFactory";
+ }
+ });
+
+ // Return the produced generic binding
+ return singletonList(binding);
+ }
+
+ return emptyList();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistry.java
new file mode 100644
index 0000000..43e1c52
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistry.java
@@ -0,0 +1,164 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.alwaysTrue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.annotations.HandlerBinding;
+import org.apache.felix.ipojo.annotations.Ignore;
+import org.apache.felix.ipojo.annotations.Stereotype;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.discovery.ChainedAnnotationDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.discovery.HandlerBindingDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.discovery.IgnoredDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.discovery.StereotypeDiscovery;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.parser.AnnotationParser;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.GenericVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.stereotype.StereotypeVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+
+/**
+ * The {@link MetaAnnotationBindingRegistry} is a registry that tries to complete its list
+ * of bindings when an unknown one is detected.
+ * It uses the given {@link ResourceStore} to parse the annotation's type and find if
+ * it's annotated with @{@link org.apache.felix.ipojo.annotations.Stereotype},
+ * @{@link org.apache.felix.ipojo.annotations.HandlerBinding} or @{@link org.apache.felix.ipojo.annotations.Ignore}
+ */
+public class MetaAnnotationBindingRegistry extends CompletableBindingRegistry {
+
+ private ResourceStore m_store;
+ private Reporter m_reporter;
+
+ public MetaAnnotationBindingRegistry(final BindingRegistry delegate, final Reporter reporter, final ResourceStore store) {
+ super(delegate, reporter);
+ this.m_reporter = reporter;
+ this.m_store = store;
+ addBindings(nullBindingsForMetaAnnotations());
+ }
+
+ protected Iterable<Binding> nullBindingsForMetaAnnotations() {
+ // Do not re-apply meta-annotations
+ ArrayList<Binding> bindings = new ArrayList<Binding>();
+ bindings.add(new NullBinding(Type.getType(Stereotype.class)));
+ bindings.add(new NullBinding(Type.getType(HandlerBinding.class)));
+ bindings.add(new NullBinding(Type.getType(Ignore.class)));
+ return bindings;
+ }
+
+ @Override
+ protected List<Binding> createBindings(final Type type) {
+
+ // Parse the annotation
+ byte[] bytes;
+ try {
+ bytes = m_store.read(type.getInternalName().concat(".class"));
+ } catch (IOException e) {
+ // Annotation type cannot be read
+ m_reporter.trace("Could not read bytecode for @%s.", type.getClassName());
+ return emptyList();
+ } catch (IllegalStateException e) {
+ m_reporter.trace("Could not read bytecode for @%s because the bundle is not in a state allowing read " +
+ "operations.",
+ type.getClassName());
+ return emptyList();
+ }
+ AnnotationParser parser = new AnnotationParser();
+ AnnotationType annotationType = parser.read(bytes);
+
+ // Search meta-annotations
+ ChainedAnnotationDiscovery chain = new ChainedAnnotationDiscovery();
+ StereotypeDiscovery stereotypeDiscovery = new StereotypeDiscovery();
+ HandlerBindingDiscovery handlerBindingDiscovery = new HandlerBindingDiscovery();
+ IgnoredDiscovery ignoredDiscovery = new IgnoredDiscovery();
+ chain.getDiscoveries().add(stereotypeDiscovery);
+ chain.getDiscoveries().add(handlerBindingDiscovery);
+ chain.getDiscoveries().add(ignoredDiscovery);
+
+ annotationType.traverse(chain);
+
+ // Produced Bindings
+ List<Binding> bindings = new ArrayList<Binding>();
+
+ // @Stereotype support
+ if (stereotypeDiscovery.isStereotype()) {
+ m_reporter.trace("@Stereotype detected: @%s", type.getClassName());
+ Binding binding = new Binding();
+ binding.setAnnotationType(type);
+ binding.setPredicate(alwaysTrue());
+ binding.setFactory(new StereotypeVisitorFactory(annotationType));
+
+ bindings.add(binding);
+ }
+
+ // @HandlerBinding support
+ if (handlerBindingDiscovery.isHandlerBinding()) {
+
+ m_reporter.trace("@HandlerBinding detected: @%s", type.getClassName());
+ Binding binding = new Binding();
+ binding.setAnnotationType(type);
+ binding.setPredicate(alwaysTrue());
+ final Element element = buildElement(handlerBindingDiscovery, type);
+ binding.setFactory(new GenericVisitorFactory(element.getName(), element.getNameSpace()));
+
+ bindings.add(binding);
+ }
+
+ // Its IMPORTANT that the @Ignore is processed last since it removes existing bindings
+ if (ignoredDiscovery.isIgnore()) {
+ m_reporter.trace("@Ignore detected: @%s", type.getClassName());
+ Binding binding = new NullBinding(type);
+
+ bindings.clear();
+ bindings.add(binding);
+ bindings = unmodifiableList(bindings); // just in case of ...
+ }
+
+ return bindings;
+
+ }
+
+ private Element buildElement(final HandlerBindingDiscovery handler, final Type type) {
+ Element element;
+ if ((handler.getNamespace() == null) &&
+ (handler.getValue() == null)) {
+ // No attributes specified, use annotation type as element's source
+ element = Elements.buildElement(type);
+ } else if ((handler.getNamespace() == null)) {
+ // Namespace attribute is omitted
+ element = Elements.buildElement(handler.getValue());
+ } else {
+ element = Elements.buildElement(handler.getNamespace(),
+ handler.getValue());
+ }
+ return element;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java
new file mode 100644
index 0000000..721e1e9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java
@@ -0,0 +1,150 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.manipulator.util.ChainedAnnotationVisitor;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link Selection} is used to select a subset of all supported {@link AnnotationVisitor}.
+ * It's a query DSL.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Selection {
+
+ private BindingRegistry registry;
+ private ComponentWorkbench workbench;
+ private Reporter reporter;
+ private FieldNode field;
+ private MethodNode method;
+ private ClassNode clazz;
+ private int index = BindingContext.NO_INDEX;
+ private String annotation;
+ private ElementType elementType = null;
+ private Object visitor;
+
+ public Selection(BindingRegistry registry, ComponentWorkbench workbench, Reporter reporter) {
+ this.registry = registry;
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ public Selection field(FieldVisitor visitor, FieldNode node) {
+ this.visitor = visitor;
+ this.field = node;
+ this.elementType = ElementType.FIELD;
+ return this;
+ }
+
+ public Selection method(MethodVisitor visitor, MethodNode node) {
+ this.visitor = visitor;
+ this.method = node;
+ this.elementType = ElementType.METHOD;
+ return this;
+ }
+
+ public Selection type(ClassVisitor visitor, ClassNode node) {
+ this.visitor = visitor;
+ this.clazz = node;
+ this.elementType = ElementType.TYPE;
+ return this;
+ }
+
+ public Selection parameter(MethodVisitor visitor, MethodNode node, int index) {
+ this.visitor = visitor;
+ this.index = index;
+ this.method = node;
+ this.elementType = ElementType.PARAMETER;
+ return this;
+ }
+
+ public Selection annotatedWith(String desc) {
+ this.annotation = desc;
+ return this;
+ }
+
+ public AnnotationVisitor get() {
+ List<AnnotationVisitor> visitors = list();
+
+ if (visitors.isEmpty()) {
+ return null;
+ }
+
+ if (visitors.size() == 1) {
+ return visitors.get(0);
+ }
+
+ ChainedAnnotationVisitor chained = new ChainedAnnotationVisitor();
+ chained.getVisitors().addAll(visitors);
+ return chained;
+ }
+
+ private List<AnnotationVisitor> list() {
+ BindingContext context;
+
+ if (elementType == ElementType.FIELD) {
+ context = new BindingContext(workbench, reporter, Type.getType(annotation), field,
+ elementType, index, visitor);
+ } else if (elementType == ElementType.TYPE) {
+ context = new BindingContext(workbench, reporter, Type.getType(annotation), clazz,
+ elementType, index, visitor);
+ } else {
+ // Parameter of method.
+ context = new BindingContext(workbench, reporter, Type.getType(annotation), method,
+ elementType, index, visitor);
+ }
+
+
+ List<Binding> predicates = registry.getBindings(annotation);
+
+ List<AnnotationVisitor> visitors = new ArrayList<AnnotationVisitor>();
+ if (predicates != null && !predicates.isEmpty()) {
+ collectMatchingVisitors(predicates, context, visitors);
+ }
+ return visitors;
+ }
+
+
+ private void collectMatchingVisitors(List<Binding> bindings, BindingContext context, List<AnnotationVisitor> visitors) {
+ for (Binding binding : bindings) {
+ if (binding.getPredicate().matches(context)) {
+ AnnotationVisitor visitor = binding.getFactory().newAnnotationVisitor(context);
+ if (visitor != null) {
+ visitors.add(visitor);
+ }
+ }
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java
new file mode 100644
index 0000000..20a35bd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java
@@ -0,0 +1,139 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parse the @Component annotation.
+ * @see org.apache.felix.ipojo.annotations.Component
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentVisitor extends AnnotationVisitor {
+
+ private Reporter reporter;
+
+ /**
+ * Element 'properties'.
+ */
+ private Element m_props = new Element("properties", "");
+
+ private Element component = new Element("component", "");
+
+ private ComponentWorkbench workbench;
+
+ public ComponentVisitor(ComponentWorkbench workbench, Reporter reporter) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Visit @Component annotation attribute.
+ * @param name attribute name
+ * @param value attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("public_factory") || name.equals("publicFactory")) {
+ // public_factory is deprecated, but must sill be supported
+ String factory = value.toString();
+ if (factory.equalsIgnoreCase("false")) {
+ component.addAttribute(new Attribute("public", "false"));
+ } else {
+ component.addAttribute(new Attribute("public", "true"));
+ }
+ return;
+ }
+
+ if (name.equals("name")) {
+ component.addAttribute(new Attribute("name", value.toString()));
+ return;
+ }
+ if (name.equals("immediate")) {
+ component.addAttribute(new Attribute("immediate", value.toString()));
+ return;
+ }
+ if (name.equals("architecture")) {
+ component.addAttribute(new Attribute("architecture", value.toString()));
+ return;
+ }
+ if (name.equals("propagation") && (value != null)) {
+ if (arePropertiesEmpty()) {
+ initComponentProperties();
+ }
+ m_props.addAttribute(new Attribute("propagation", value.toString()));
+ return;
+ }
+ if (name.equals("managedservice") && (value != null)) {
+ if (arePropertiesEmpty()) {
+ initComponentProperties();
+ }
+ m_props.addAttribute(new Attribute("pid", value.toString()));
+ return;
+ }
+ if ((name.equals("factory_method") || name.equals("factoryMethod")) && (value != null)) {
+ // factory_method is deprecated, but must still be supported.
+ component.addAttribute(new Attribute("factory-method", value.toString()));
+ return;
+ }
+ if (name.equals("version") && (value != null)) {
+ component.addAttribute(new Attribute("version", value.toString()));
+ }
+ }
+
+ private boolean arePropertiesEmpty() {
+ return m_props.getElements().length == 0;
+ }
+
+ private void initComponentProperties() {
+ workbench.getElements().put(m_props, null);
+ workbench.getIds().put("properties", m_props);
+ }
+
+ /**
+ * End of the visit.
+ * Append to the "component" element computed attribute.
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ String classname = workbench.getType().getClassName();
+
+ if (component.getAttribute("name") == null) {
+ component.addAttribute(new Attribute("name", classname));
+ }
+
+ component.addAttribute(new Attribute("classname", classname));
+
+ if (workbench.getRoot() == null) {
+ workbench.setRoot(component);
+ } else {
+ // Error case: 2 component type's annotations (@Component and @Handler for example) on the same class
+ reporter.error("Multiple 'component type' annotations on the class '{%s}'.", classname);
+ reporter.warn("@Component will be ignored.");
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java
new file mode 100644
index 0000000..88081f0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parses the @Controller annotation.
+ * @see org.apache.felix.ipojo.annotations.Controller
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ControllerVisitor extends AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+
+ private String field;
+
+ public ControllerVisitor(ComponentWorkbench workbench, String field) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.field = field;
+ }
+
+ /**
+ * Visit @Handler annotation attributes.
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visitEnd() {
+ Element controller = new Element("controller", "");
+ controller.addAttribute(new Attribute("field", field));
+ workbench.getElements().put(controller, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java
new file mode 100644
index 0000000..1d6bec9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java
@@ -0,0 +1,164 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parses a Property or ServiceProperty annotation.
+ * @see org.apache.felix.ipojo.annotations.ServiceProperty
+ * @see org.apache.felix.ipojo.annotations.Property
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldPropertyVisitor extends AnnotationVisitor {
+
+ /**
+ * Parent element element.
+ */
+ private Element m_parent;
+
+ /**
+ * Field name.
+ */
+ private String m_field;
+
+ /**
+ * Property name.
+ */
+ private String m_name;
+
+ /**
+ * Property value.
+ */
+ private String m_value;
+
+ /**
+ * Property mandatory aspect.
+ */
+ private String m_mandatory;
+
+ /**
+ * Property type.
+ */
+ private String m_type;
+
+ /**
+ * Property immutable aspect.
+ */
+ private String m_immutable;
+
+
+ /**
+ * Constructor without field
+ * @param parent : element element..
+ */
+ public FieldPropertyVisitor(Element parent) {
+ this(null, parent);
+ }
+
+ /**
+ * Constructor.
+ * @param parent : element element.
+ * @param field : field name.
+ */
+ public FieldPropertyVisitor(String field, Element parent) {
+ super(Opcodes.ASM5);
+ m_parent = parent;
+ m_field = field;
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ m_name = value.toString();
+ return;
+ }
+ if (name.equals("value")) {
+ m_value = value.toString();
+ return;
+ }
+ if (name.equals("mandatory")) {
+ m_mandatory = value.toString();
+ return;
+ }
+ if (name.equals("immutable")) {
+ m_immutable = value.toString();
+ return;
+ }
+ if (name.equals("type")) {
+ m_type = value.toString();
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "property" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_field != null && m_name == null) {
+ m_name = m_field;
+ }
+
+
+ Element[] props = m_parent.getElements("property");
+ Element prop = null;
+ for (int i = 0; prop == null && props != null && i < props.length; i++) {
+ String name = props[i].getAttribute("name");
+ if (name != null && name.equals(m_name)) {
+ prop = props[i];
+ }
+ }
+
+ if (prop == null) {
+ prop = new Element("property", "");
+ m_parent.addElement(prop);
+ if (m_name != null) {
+ prop.addAttribute(new Attribute("name", m_name));
+ }
+ }
+
+ if (m_field != null) {
+ prop.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_type != null) {
+ prop.addAttribute(new Attribute("type", m_type));
+ }
+
+ if (m_value != null) {
+ prop.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_mandatory != null) {
+ prop.addAttribute(new Attribute("mandatory", m_mandatory));
+ }
+ if (m_immutable != null) {
+ prop.addAttribute(new Attribute("immutable", m_immutable));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java
new file mode 100644
index 0000000..2c52783
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java
@@ -0,0 +1,160 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Parse the @HandlerDeclaration annotation.
+ * @see org.apache.felix.ipojo.annotations.HandlerDeclaration
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerDeclarationVisitor extends AnnotationVisitor {
+
+ /**
+ * XML accepted by the handler.
+ */
+ private String m_value;
+
+ private DocumentBuilder builder;
+
+ private ComponentWorkbench workbench;
+ private Reporter reporter;
+
+ public HandlerDeclarationVisitor(ComponentWorkbench workbench, DocumentBuilder builder, Reporter reporter) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.builder = builder;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Parses the value attribute.
+ * @param name 'value'
+ * @param value the value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ // there is only a 'value' attribute
+ this.m_value = (String) value;
+ }
+
+ /**
+ * End of the visit.
+ * Builds the XML document.
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // The value is an XML document
+ InputStream is = new ByteArrayInputStream(m_value.getBytes());
+ Document document = null;
+ try {
+ document = builder.parse(is);
+ Element e = convertDOMElements(document.getDocumentElement());
+ workbench.getElements().put(e, null);
+ } catch (Exception e) {
+ reporter.warn("Cannot convert {} to iPOJO Elements.", m_value, e);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ reporter.trace("Cannot close correctly the value input stream ({}).", m_value, e);
+ }
+ }
+ }
+
+ /**
+ * Converts recursively the given XML Element into an iPOJO Element.
+ * @param xmlElement DOM Element to be converted
+ */
+ private static Element convertDOMElements(final org.w3c.dom.Element xmlElement) {
+
+ // Create an equivalent iPOJO element
+ Element converted = transformElement(xmlElement);
+
+ convertDOMElements(converted, xmlElement);
+
+ return converted;
+ }
+
+ /**
+ * Converts recursively the given XML Element into an iPOJO Element.
+ * @param root iPOJO root Element
+ * @param xmlElement DOM Element to be converted
+ */
+ private static void convertDOMElements(final Element root,
+ final org.w3c.dom.Element xmlElement) {
+
+ // Convert attributes if any
+ if (xmlElement.hasAttributes()) {
+ NamedNodeMap attributes = xmlElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Attr attr = (Attr) attributes.item(i);
+ if (!"xmlns".equals(attr.getPrefix())) {
+ root.addAttribute(transformAttribute(attr));
+ }
+ }
+ }
+
+ // Convert child elements if any
+ if (xmlElement.hasChildNodes()) {
+ NodeList children = xmlElement.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+
+ // Create an equivalent iPOJO element
+ org.w3c.dom.Element child = (org.w3c.dom.Element) children.item(i);
+ Element converted = transformElement(child);
+
+ // Add converted element as a root's child
+ root.addElement(converted);
+
+ // Recursive call
+ convertDOMElements(converted, child);
+ }
+ }
+
+ }
+
+ private static Attribute transformAttribute(Attr attr) {
+ return new Attribute(attr.getLocalName(),
+ attr.getNamespaceURI(),
+ attr.getValue());
+ }
+
+ private static Element transformElement(org.w3c.dom.Element xmlElement) {
+ return new Element(xmlElement.getLocalName(), xmlElement.getNamespaceURI());
+ }
+
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java
new file mode 100644
index 0000000..ae97861
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parses the @Handler annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Handler
+ */
+public class HandlerVisitor extends AnnotationVisitor {
+
+ private Element handler = new Element("handler", "");
+
+ private ComponentWorkbench workbench;
+
+ private Reporter reporter;
+
+ public HandlerVisitor(ComponentWorkbench workbench, Reporter reporter) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Visit @Handler annotation attributes.
+ *
+ * @param name : annotation attribute name
+ * @param value : annotation attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ handler.addAttribute(new Attribute("name", value.toString()));
+ return;
+ }
+ if (name.equals("namespace")) {
+ handler.addAttribute(new Attribute("namespace", value.toString()));
+ return;
+ }
+ if (name.equals("level")) {
+ handler.addAttribute(new Attribute("level", value.toString()));
+ return;
+ }
+ if (name.equals("architecture")) {
+ handler.addAttribute(new Attribute("architecture", value.toString()));
+ }
+ }
+
+
+ /**
+ * End of the visit.
+ * Append to the "component" element computed attribute.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ String classname = workbench.getType().getClassName();
+ handler.addAttribute(new Attribute("classname", classname));
+
+ if (workbench.getRoot() == null) {
+ workbench.setRoot(handler);
+ } else {
+ // Error case: 2 component type's annotations (@Component and @Handler for example) on the same class
+ reporter.error("Multiple 'component type' annotations on the class '{%s}'.", classname);
+ reporter.warn("@Handler will be ignored.");
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java
new file mode 100644
index 0000000..7cf43cb
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java
@@ -0,0 +1,71 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parse the @Instantitate annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Instantiate
+ */
+public class InstantiateVisitor extends AnnotationVisitor {
+
+ private Element instance = new Element("instance", "");
+
+ private ComponentWorkbench workbench;
+
+ public InstantiateVisitor(ComponentWorkbench workbench) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ }
+
+ /**
+ * Visit an annotation attribute.
+ *
+ * @param name the attribute name
+ * @param value the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ instance.addAttribute(new Attribute("name", (String) value));
+ }
+ }
+
+ /**
+ * End of the visit. Creates the instance element.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // We set the instance's component attribute to the class name, if the component type has a custom name,
+ // we will update it.
+ instance.addAttribute(new Attribute("component", workbench.getType().getClassName()));
+
+ workbench.setInstance(instance);
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java
new file mode 100644
index 0000000..08cf660
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parse @Validate and @Invalidate annotations.
+ * @see org.apache.felix.ipojo.annotations.Validate
+ * @see org.apache.felix.ipojo.annotations.Invalidate
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LifecycleVisitor extends AnnotationVisitor {
+
+ public static enum Transition {
+ VALIDATE, INVALIDATE
+ }
+
+ private ComponentWorkbench workbench;
+ private String name;
+ private Transition transition;
+
+ public LifecycleVisitor(ComponentWorkbench workbench, String name, Transition transition) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.name = name;
+ this.transition = transition;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element cb = new Element("callback", "");
+ cb.addAttribute(new Attribute("transition", transition.name().toLowerCase()));
+ cb.addAttribute(new Attribute("method", name));
+ workbench.getElements().put(cb, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java
new file mode 100644
index 0000000..898c740
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java
@@ -0,0 +1,177 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodPropertyVisitor extends AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element m_parent;
+
+ /**
+ * Attached method.
+ */
+ private String m_method;
+
+ /**
+ * Property name.
+ */
+ private String m_name;
+
+ /**
+ * Property id.
+ */
+ private String m_id;
+
+ /**
+ * Property value.
+ */
+ private String m_value;
+
+ /**
+ * Property mandatory aspect.
+ */
+ private String m_mandatory;
+
+ /**
+ * Property immutable aspect.
+ */
+ private String m_immutable;
+
+ /**
+ * Constructor.
+ *
+ * @param parent : element element.
+ * @param method : attached method.
+ */
+ public MethodPropertyVisitor(Element parent, String method) {
+ super(Opcodes.ASM5);
+ m_parent = parent;
+ m_method = method;
+ }
+
+ /**
+ * Visit annotation attributes.
+ *
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ m_name = value.toString();
+ return;
+ }
+ if (name.equals("value")) {
+ m_value = value.toString();
+ return;
+ }
+ if (name.equals("mandatory")) {
+ m_mandatory = value.toString();
+ return;
+ }
+ if (name.equals("immutable")) {
+ m_immutable = value.toString();
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ }
+ }
+
+ /**
+ * End of the visit.
+ * Append the computed element to the element element.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element prop = visitEndCommon();
+
+ prop.addAttribute(new Attribute("method", m_method));
+
+ }
+
+ protected Element visitEndCommon() {
+ m_method = computeEffectiveMethodName(m_method);
+
+ // If neither name nor id is provided, try to extract the name
+ if (m_name == null && m_id == null && m_method.startsWith("set")) {
+ m_name = m_method.substring("set".length());
+ m_id = m_name;
+ // Else align the two values
+ } else if (m_name != null && m_id == null) {
+ m_id = m_name;
+ } else if (m_id != null && m_name == null) {
+ m_name = m_id;
+ }
+
+ Element prop = getPropertyElement();
+
+ if (m_value != null) {
+ prop.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_mandatory != null) {
+ prop.addAttribute(new Attribute("mandatory", m_mandatory));
+ }
+ if (m_immutable != null) {
+ prop.addAttribute(new Attribute("immutable", m_immutable));
+ }
+
+ return prop;
+ }
+
+ private Element getPropertyElement() {
+
+ // Gather all the <property> Elements
+ Element[] props = m_parent.getElements("property");
+ Element prop = null;
+ for (int i = 0; props != null && prop == null && i < props.length; i++) {
+
+ // Get the first one with the good name
+ String name = props[i].getAttribute("name");
+ if (name != null && name.equals(m_name)) {
+ prop = props[i];
+ }
+ }
+
+ // Create the Element if not present
+ if (prop == null) {
+ prop = new Element("property", "");
+ m_parent.addElement(prop);
+ if (m_name != null) {
+ prop.addAttribute(new Attribute("name", m_name));
+ }
+ }
+
+ return prop;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java
new file mode 100644
index 0000000..208728d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java
@@ -0,0 +1,66 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterPropertyVisitor extends MethodPropertyVisitor {
+
+ /**
+ * If this is a parameter annotation, the index of the parameter.
+ */
+ private int m_index = -1;
+
+ private MethodNode node;
+
+ /**
+ * Constructor.
+ *
+ * @param parent : element element.
+ * @param method : attached method.
+ * @param index : the parameter index
+ */
+ public ParameterPropertyVisitor(Element parent, MethodNode method, int index) {
+ super(parent, method.name);
+ this.node = method;
+ m_index = index;
+ }
+
+ /**
+ * End of the visit.
+ * Append the computed element to the element element.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element prop = visitEndCommon();
+ String type = Type.getArgumentTypes(node.desc)[m_index].getClassName();
+ prop.addAttribute(new Attribute("type", type));
+ prop.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java
new file mode 100644
index 0000000..00a6c22
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.PostRegistration
+ */
+public class PostRegistrationVisitor extends AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public PostRegistrationVisitor(ComponentWorkbench workbench, String name) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element provides;
+ if (workbench.getIds().containsKey("provides")) {
+ provides = workbench.getIds().get("provides");
+ provides.addAttribute(new Attribute("post-registration", name));
+ }
+ // Else ignore annotation ...
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java
new file mode 100644
index 0000000..cd24451
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * @see org.apache.felix.ipojo.annotations.PostUnregistration
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PostUnregistrationVisitor extends AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public PostUnregistrationVisitor(ComponentWorkbench workbench, String name) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element provides;
+ if (workbench.getIds().containsKey("provides")) {
+ provides = workbench.getIds().get("provides");
+ provides.addAttribute(new Attribute("post-unregistration", name));
+ }
+ // Else ignore annotation ...
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java
new file mode 100644
index 0000000..dcce996
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java
@@ -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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Parse the @Provides annotation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Provides
+ */
+public class ProvidesVisitor extends AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+
+ /**
+ * Provides element.
+ */
+ private Element m_prov = new Element("provides", "");
+
+ public ProvidesVisitor(ComponentWorkbench workbench) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ }
+
+ /**
+ * Visit @provides annotation attributes.
+ *
+ * @param name : annotation attribute name
+ * @param value : annotation attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("factory")) { // Should be deprecated
+ m_prov.addAttribute(new Attribute("factory", value.toString()));
+ }
+ if (name.equals("strategy")) {
+ m_prov.addAttribute(new Attribute("strategy", value.toString()));
+ }
+ }
+
+ /**
+ * Visit specifications array.
+ *
+ * @param name : attribute name
+ * @return a visitor visiting each element of the array.
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String name) {
+ if (name.equals("specifications")) {
+ return new InterfaceArrayVisitor();
+ } else if (name.equals("properties")) {
+ // Create a new simple visitor to visit the nested ServiceProperty annotations
+ // Collected properties are collected in m_prov
+ return new AnnotationVisitor(Opcodes.ASM5) {
+ public AnnotationVisitor visitAnnotation(String ignored, String desc) {
+ return new FieldPropertyVisitor(m_prov);
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * End of the visit.
+ * Append to the element element the computed "provides" element.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ workbench.getIds().put("provides", m_prov);
+ workbench.getElements().put(m_prov, null);
+ }
+
+ private class InterfaceArrayVisitor extends AnnotationVisitor {
+ /**
+ * List of parsed interface.
+ */
+ private String m_itfs;
+
+
+ public InterfaceArrayVisitor() {
+ super(Opcodes.ASM5);
+ }
+
+ /**
+ * Visit one element of the array.
+ *
+ * @param arg0 : null
+ * @param arg1 : element value.
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ if (m_itfs == null) {
+ m_itfs = "{" + ((Type) arg1).getClassName();
+ } else {
+ m_itfs += "," + ((Type) arg1).getClassName();
+ }
+ }
+
+ /**
+ * End of the array visit.
+ * Add the attribute to 'provides' element.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ m_prov.addAttribute(new Attribute("specifications", m_itfs + "}"));
+ }
+
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
new file mode 100644
index 0000000..9213949
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
@@ -0,0 +1,268 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * AnnotationVisitor parsing the @Requires annotation.
+ * @see org.apache.felix.ipojo.annotations.Requires
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class RequiresVisitor extends AnnotationVisitor {
+
+
+ private ComponentWorkbench workbench;
+
+ /**
+ * Dependency field.
+ */
+ private String m_field;
+
+ /**
+ * Dependency filter.
+ */
+ private String m_filter;
+
+ /**
+ * Is the dependency optional ?
+ */
+ private String m_optional;
+
+ /**
+ * Dependency specification.
+ */
+ private String m_specification;
+
+ /**
+ * Dependency id.
+ */
+ private String m_id;
+
+ /**
+ * Binding policy.
+ */
+ private String m_policy;
+
+ /**
+ * Default-Implementation attribute.
+ */
+ private String m_defaultImplementation;
+
+ /**
+ * Exception attribute.
+ */
+ private String m_exception;
+
+ /**
+ * Enable or Disable Nullable pattern.
+ */
+ private String m_nullable;
+
+ /**
+ * Comparator.
+ */
+ private String m_comparator;
+
+ /**
+ * From attribute.
+ */
+ private String m_from;
+
+ /**
+ * Proxy attribute.
+ */
+ private String m_proxy;
+
+ /**
+ * Timeout attribute.
+ */
+ private String m_timeout;
+
+ /**
+ * Constructor.
+ * @param name : field name.
+ */
+ public RequiresVisitor(ComponentWorkbench workbench, String name) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.m_field = name;
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("filter")) {
+ m_filter = value.toString();
+ return;
+ }
+ if (name.equals("optional")) {
+ m_optional = value.toString();
+ return;
+ }
+ if (name.equals("nullable")) {
+ m_nullable = value.toString();
+ return;
+ }
+ // Used by component using the pre 1.11 version of annotations.
+ if (name.equals("policy")) {
+ m_policy = getPolicy(value.toString());
+ return;
+ }
+ if (name.equals("defaultimplementation")) {
+ Type type = Type.getType(value.toString());
+ m_defaultImplementation = type.getClassName();
+ return;
+ }
+ if (name.equals("exception")) {
+ Type type = Type.getType(value.toString());
+ m_exception = type.getClassName();
+ return;
+ }
+ if (name.equals("specification")) {
+ // Detect whether it's an internal class name.
+ if (value.toString().startsWith("L") && value.toString().endsWith(";")) {
+ Type type = Type.getType(value.toString());
+ m_specification = type.getClassName();
+ } else {
+ m_specification = value.toString();
+ }
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ return;
+ }
+ if (name.equals("comparator")) {
+ Type type = Type.getType(value.toString());
+ m_comparator = type.getClassName();
+ return;
+ }
+ if (name.equals("from")) {
+ m_from = value.toString();
+ return;
+ }
+ if (name.equals("proxy")) {
+ m_proxy = value.toString();
+ }
+ if (name.equals("timeout")) {
+ m_timeout = value.toString();
+ }
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ if (name.equals("policy")) {
+ m_policy = getPolicy(value);
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "requires" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element requires;
+ if (m_id == null) {
+ requires = workbench.getIds().get(m_field);
+ } else {
+ requires = workbench.getIds().get(m_id);
+ }
+
+ if (requires == null) {
+ requires = new Element("requires", "");
+ }
+
+ requires.addAttribute(new Attribute("field", m_field));
+ if (m_specification != null) {
+ requires.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_filter != null) {
+ requires.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_optional != null) {
+ requires.addAttribute(new Attribute("optional", m_optional));
+ }
+ if (m_nullable != null) {
+ requires.addAttribute(new Attribute("nullable", m_nullable));
+ }
+ if (m_defaultImplementation != null) {
+ requires.addAttribute(new Attribute("default-implementation", m_defaultImplementation));
+ }
+ if (m_exception != null) {
+ requires.addAttribute(new Attribute("exception", m_exception));
+ }
+ if (m_policy != null) {
+ requires.addAttribute(new Attribute("policy", m_policy));
+ }
+ if (m_id != null) {
+ requires.addAttribute(new Attribute("id", m_id));
+ }
+ if (m_comparator != null) {
+ requires.addAttribute(new Attribute("comparator", m_comparator));
+ }
+ if (m_from != null) {
+ requires.addAttribute(new Attribute("from", m_from));
+ }
+ if (m_proxy != null) {
+ requires.addAttribute(new Attribute("proxy", m_proxy));
+ }
+ if (m_timeout != null) {
+ requires.addAttribute(new Attribute("timeout", m_timeout));
+ }
+
+ if (m_id != null) {
+ workbench.getIds().put(m_id, requires);
+ } else {
+ workbench.getIds().put(m_field, requires);
+ }
+
+ workbench.getElements().put(requires, null);
+ }
+
+ /**
+ * Gets the iPOJO binding policy name from the given value.
+ * @param policy the read policy
+ * @return the policy name
+ */
+ public static String getPolicy(String policy) {
+ if (policy.equalsIgnoreCase("static")) {
+ return "static";
+ }
+ if (policy.equalsIgnoreCase("dynamic")) {
+ return "dynamic";
+ }
+ // The _ is used in the annotation.
+ if (policy.equalsIgnoreCase("dynamic_priority")) {
+ return "dynamic-priority";
+ }
+ return policy;
+ }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java
new file mode 100644
index 0000000..422bb9d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java
@@ -0,0 +1,81 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Parses a @ServiceController annotation.
+ * @see org.apache.felix.ipojo.annotations.ServiceController
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceControllerVisitor extends AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element provides;
+
+ /**
+ * Provides element.
+ */
+ private Element controller = new Element("controller", "");
+
+ /**
+ * Constructor.
+ * @param provides : element element.
+ * @param field : field name.
+ */
+ public ServiceControllerVisitor(String field, Element provides) {
+ super(Opcodes.ASM5);
+ this.provides = provides;
+ controller.addAttribute(new Attribute("field", field));
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("value")) {
+ controller.addAttribute(new Attribute("value", value.toString()));
+ return;
+ }
+ if (name.equals("specification")) {
+ String spec = ((Type) value).getClassName();
+ controller.addAttribute(new Attribute("specification", spec));
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "controller" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ provides.addElement(controller);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java
new file mode 100644
index 0000000..dd4b379
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.annotations.Updated
+ */
+public class UpdatedVisitor extends AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public UpdatedVisitor(ComponentWorkbench workbench, String name) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element properties = Elements.getPropertiesElement(workbench);
+ properties.addAttribute(new Attribute("updated", name));
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java
new file mode 100644
index 0000000..a00bed6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java
@@ -0,0 +1,223 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.RequiresVisitor;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbstractBindVisitor extends AnnotationVisitor {
+
+ protected ComponentWorkbench workbench;
+ protected Action action;
+
+ public AbstractBindVisitor(ComponentWorkbench workbench, Action action) {
+ super(Opcodes.ASM5);
+ this.workbench = workbench;
+ this.action = action;
+ }
+
+ /**
+ * Requirement filter.
+ */
+ protected String m_filter;
+ /**
+ * Is the requirement optional?
+ */
+ protected String m_optional;
+ /**
+ * Is the requirement aggregate?
+ */
+ protected String m_aggregate;
+ /**
+ * Required specification.
+ */
+ protected String m_specification;
+ /**
+ * Requirement id.
+ */
+ protected String m_id;
+ /**
+ * Binding policy.
+ */
+ protected String m_policy;
+ /**
+ * Comparator.
+ */
+ protected String m_comparator;
+ /**
+ * From attribute.
+ */
+ protected String m_from;
+
+ /**
+ * proxy attribute.
+ */
+ protected String m_proxy;
+
+ /**
+ * Visit annotation's attributes.
+ *
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("filter")) {
+ m_filter = value.toString();
+ return;
+ }
+ if (name.equals("optional")) {
+ m_optional = value.toString();
+ return;
+ }
+ if (name.equals("aggregate")) {
+ m_aggregate = value.toString();
+ return;
+ }
+ if (name.equals("specification")) {
+ // Detect whether it's an internal class name.
+ if (value.toString().startsWith("L") && value.toString().endsWith(";")) {
+ Type type = Type.getType(value.toString());
+ m_specification = type.getClassName();
+ } else {
+ m_specification = value.toString();
+ }
+ return;
+ }
+ // Still used by component using the old version of the annotations.
+ if (name.equals("policy")) {
+ m_policy = RequiresVisitor.getPolicy(value.toString());
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ return;
+ }
+ if (name.equals("comparator")) {
+ Type type = Type.getType(value.toString());
+ m_comparator = type.getClassName();
+ return;
+ }
+ if (name.equals("from")) {
+ m_from = value.toString();
+ }
+ if (name.equals("proxy")) {
+ m_proxy = value.toString();
+ }
+
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ if (name.equals("policy")) {
+ m_policy = RequiresVisitor.getPolicy(value);
+ }
+ }
+
+ public void visitEnd() {
+ }
+
+ protected Element getRequiresElement() {
+
+ // Check if it is a full-determined requirement
+ Element requires = workbench.getIds().get(m_id);
+ if (requires == null) {
+ // Add the complete requires
+ requires = createRequiresElement();
+ } else {
+ if (!completeExistingRequires(requires))
+ return null;
+ }
+
+ return requires;
+ }
+
+ protected boolean completeExistingRequires(Element requires) {
+ return
+ completeAttribute(requires, "specification", m_specification)
+ && completeAttribute(requires, "optional", m_optional)
+ && completeAttribute(requires, "aggregate", m_aggregate)
+ && completeAttribute(requires, "filter", m_filter)
+ && completeAttribute(requires, "policy", m_policy)
+ && completeAttribute(requires, "comparator", m_comparator)
+ && completeAttribute(requires, "from", m_from)
+ && completeAttribute(requires, "proxy", m_proxy);
+ }
+
+ private boolean completeAttribute(Element requires, String name, String value) {
+ // If we have a value
+ if (value != null) {
+
+ String old = requires.getAttribute(name);
+ if (old == null) {
+ // If the old value was not set, just set the new value
+ requires.addAttribute(new Attribute(name, value));
+ } else if (!value.equals(old)) {
+ //
+ System.err.println("The '" + name + "' attribute has changed: " + old + " -> " + value);
+ return false;
+ } // Otherwise, the old and new value are equals
+ }
+ return true;
+ }
+
+ protected Element createRequiresElement() {
+ Element requires;
+ requires = new Element("requires", "");
+ if (m_specification != null) {
+ requires.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_aggregate != null) {
+ requires.addAttribute(new Attribute("aggregate", m_aggregate));
+ }
+ if (m_filter != null) {
+ requires.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_optional != null) {
+ requires.addAttribute(new Attribute("optional", m_optional));
+ }
+ if (m_policy != null) {
+ requires.addAttribute(new Attribute("policy", m_policy));
+ }
+ if (m_id != null) {
+ requires.addAttribute(new Attribute("id", m_id));
+ }
+ if (m_comparator != null) {
+ requires.addAttribute(new Attribute("comparator", m_comparator));
+ }
+ if (m_from != null) {
+ requires.addAttribute(new Attribute("from", m_from));
+ }
+ if (m_proxy != null) {
+ requires.addAttribute(new Attribute("proxy", m_proxy));
+ }
+ return requires;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java
new file mode 100644
index 0000000..5ed64a1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java
@@ -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.felix.ipojo.manipulator.metadata.annotation.visitor.bind;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public enum Action {
+ BIND, MODIFIED, UNBIND
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java
new file mode 100644
index 0000000..a09a5d2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java
@@ -0,0 +1,89 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.MethodNode;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * Parse @Bind & @Unbind annotations on methods.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodBindVisitor extends AbstractBindVisitor {
+
+ /**
+ * Method name.
+ */
+ private MethodNode m_node;
+
+ /**
+ * Error reporter.
+ */
+ private Reporter m_reporter;
+
+ public MethodBindVisitor(ComponentWorkbench workbench, Action action, MethodNode method, Reporter reporter) {
+ super(workbench, action);
+ this.m_node = method;
+ this.m_reporter = reporter;
+ }
+
+ /**
+ * End of the visit.
+ * Create or append the requirement info to a created or already existing "requires" element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_id == null) {
+ String identifier = Names.getMethodIdentifier(m_node);
+ if (identifier != null) {
+ m_id = identifier;
+ } else {
+ if (m_specification != null) {
+ m_id = m_specification;
+ } else {
+ m_reporter.error("Cannot determine the requires identifier for the (%s) %s method: %s",
+ computeEffectiveMethodName(m_node.name),
+ action.name(),
+ "Either 'id' attribute is missing or method name do not follow the bind/set/add/modified " +
+ "naming pattern, or no specification (service interface) can be found in method signature " +
+ "or specified in annotation. Dependency will be ignored (would cause an Exception at runtime)");
+ return;
+ }
+ }
+ }
+
+ Element requires = getRequiresElement();
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("method", computeEffectiveMethodName(m_node.name)));
+ callback.addAttribute(new Attribute("type", action.name().toLowerCase()));
+ requires.addElement(callback);
+
+ workbench.getIds().put(m_id, requires);
+ workbench.getElements().put(requires, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java
new file mode 100644
index 0000000..b3063ee
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java
@@ -0,0 +1,63 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Parse @Bind & @Unbind annotations on method's parameters.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterBindVisitor extends AbstractBindVisitor {
+
+ /**
+ * For annotation parameter,
+ * the parameter index.
+ */
+ private int m_index;
+
+ public ParameterBindVisitor(ComponentWorkbench workbench, Action action, int index) {
+ super(workbench, action);
+ m_index = index;
+ }
+
+ /**
+ * End of the visit.
+ * Create or append the requirement info to a created or already existing "requires" element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_id == null) {
+ m_id = Integer.toString(m_index);
+ }
+
+ Element requires = getRequiresElement();
+
+ // Specific for parameters
+ requires.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+
+ workbench.getIds().put(m_id, requires);
+ workbench.getElements().put(requires, null);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java
new file mode 100644
index 0000000..b2edce0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java
@@ -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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.FieldNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldGenericVisitor extends RootGenericVisitor {
+ public FieldGenericVisitor(ComponentWorkbench workbench, Element element, FieldNode node) {
+ super(workbench, element, ElementType.FIELD);
+ element.addAttribute(new Attribute("field", node.name));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java
new file mode 100644
index 0000000..caf1216
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java
@@ -0,0 +1,114 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Array;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class GenericVisitor extends AnnotationVisitor {
+ protected Element element;
+
+ public GenericVisitor(Element element) {
+ super(Opcodes.ASM5);
+ this.element = element;
+ }
+
+ /**
+ * Visit a 'simple' annotation attribute.
+ * This method is used for primitive arrays too.
+ *
+ * @param name : attribute name
+ * @param value : attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (value.getClass().isArray()) {
+ // Primitive arrays case
+ String v = null;
+ int index = Array.getLength(value);
+ for (int i = 0; i < index; i++) {
+ if (v == null) {
+ v = "{" + Array.get(value, i);
+ } else {
+ v += "," + Array.get(value, i);
+ }
+ }
+ v += "}";
+ element.addAttribute(new Attribute(name, v));
+ return;
+ }
+
+ // Attributes are added as normal attributes
+ if (!(value instanceof Type)) {
+ element.addAttribute(new Attribute(name, value.toString()));
+ } else {
+ // Attributes of type class need a special handling
+ element.addAttribute(new Attribute(name, ((Type) value).getClassName()));
+ }
+
+ }
+
+ /**
+ * Visit a sub-annotation.
+ *
+ * @param name : attribute name.
+ * @param descriptor : annotation description
+ * @return an annotation visitor which will visit the given annotation
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+ // Sub annotations are mapped to sub-elements
+ Element sub = Elements.buildElement(Type.getType(descriptor));
+ element.addElement(sub);
+ return new GenericVisitor(sub);
+ }
+
+ /**
+ * Visit an array attribute.
+ *
+ * @param name : attribute name
+ * @return a visitor which will visit each element of the array
+ * @see org.objectweb.asm.AnnotationVisitor#visitArray(String)
+ */
+ public AnnotationVisitor visitArray(String name) {
+ return new SubArrayVisitor(element, name);
+ }
+
+ /**
+ * Visits an enumeration attribute.
+ *
+ * @param name the attribute name
+ * @param desc the enumeration descriptor
+ * @param value the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)
+ */
+ public void visitEnum(String name, String desc, String value) {
+ element.addAttribute(new Attribute(name, value));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitorFactory.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitorFactory.java
new file mode 100644
index 0000000..eefa6bc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitorFactory.java
@@ -0,0 +1,70 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 14:41
+ */
+public class GenericVisitorFactory implements AnnotationVisitorFactory {
+ private final String m_name;
+ private final String m_namespace;
+
+ public GenericVisitorFactory(final String name, final String namespace) {
+ m_name = name;
+ m_namespace = namespace;
+ }
+
+ // Need to build a new Element instance for each created visitor
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ if (context.getClassNode() != null) {
+ return new TypeGenericVisitor(context.getWorkbench(),
+ new Element(m_name, m_namespace));
+ } else if (context.getFieldNode() != null) {
+ return new FieldGenericVisitor(context.getWorkbench(),
+ new Element(m_name, m_namespace),
+ context.getFieldNode());
+
+ } else if ((context.getMethodNode() != null) &&
+ (context.getParameterIndex() == BindingContext.NO_INDEX)) {
+ return new MethodGenericVisitor(context.getWorkbench(),
+ new Element(m_name, m_namespace),
+ context.getMethodNode());
+ } else {
+ // last case: method parameter annotation
+ return new ParameterGenericVisitor(context.getWorkbench(),
+ new Element(m_name, m_namespace),
+ context.getMethodNode(),
+ context.getParameterIndex());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "GenericVisitorFactory";
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java
new file mode 100644
index 0000000..29c558a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java
@@ -0,0 +1,39 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodGenericVisitor extends RootGenericVisitor {
+ public MethodGenericVisitor(ComponentWorkbench workbench, Element element, MethodNode node) {
+ super(workbench, element, ElementType.METHOD);
+ element.addAttribute(new Attribute("method", computeEffectiveMethodName(node.name)));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java
new file mode 100644
index 0000000..c3e59e7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterGenericVisitor extends RootGenericVisitor {
+ private int index;
+ private MethodNode node;
+
+ public ParameterGenericVisitor(ComponentWorkbench workbench, Element element, MethodNode node, int index) {
+ super(workbench, element, ElementType.PARAMETER);
+ this.node = node;
+ this.index = index;
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+
+ String type = Type.getArgumentTypes(node.desc)[index].getClassName();
+ // TODO Is the 'index' attribute required ?
+ element.addAttribute(new Attribute("index", Integer.toString(index)));
+ element.addAttribute(new Attribute("type", type));
+ element.addAttribute(new Attribute("constructor-parameter", Integer.toString(index)));
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java
new file mode 100644
index 0000000..9a96b41
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java
@@ -0,0 +1,109 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class RootGenericVisitor extends GenericVisitor {
+ private ComponentWorkbench workbench;
+
+ /**
+ * Id attribute (if found)
+ * else use the annotation package name.
+ */
+ private String m_id;
+
+ /**
+ * Parent attribute (if found)
+ * else use the annotation package name.
+ */
+ private String m_parent;
+
+ /**
+ * Describes the structure that supports the traversed annotation.
+ */
+ private ElementType type;
+
+ public RootGenericVisitor(ComponentWorkbench workbench, Element element, ElementType type) {
+ super(element);
+ this.workbench = workbench;
+ this.type = type;
+ }
+
+ /**
+ * Visit a 'simple' annotation attribute.
+ * This method is used for primitive arrays too.
+ * @param name : attribute name
+ * @param value : attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ super.visit(name, value);
+
+ if (name.equals("id")) {
+ m_id = value.toString();
+ } else if (name.equals("parent")) {
+ m_parent = value.toString();
+ }
+ }
+
+
+
+ /**
+ * End of the visit.
+ * All attribute were visited, we can update collectors data.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ if (m_id != null) {
+ // An ID has been provided as annotation attribute
+ // Register our element under that ID
+ workbench.getIds().put(m_id, element);
+ } else {
+ // No ID provided, generate a new one from the element's namespace (aka handler's namespace)
+ m_id = element.getNameSpace();
+ if (m_id != null && !workbench.getIds().containsKey(m_id) && isClassType()) {
+ // No Elements were already registered under that namespace
+ workbench.getIds().put(m_id, element);
+ } else {
+ // ID already registered by another annotation
+ if (m_parent == null) {
+ // If no parent specified, place this element under the 'class level' Element (default)
+ m_parent = element.getNameSpace();
+ } // Otherwise, place this element under the specified Element (contribution)
+ }
+ }
+
+ workbench.getElements().put(element, m_parent);
+
+ }
+
+ private boolean isClassType() {
+ return ElementType.TYPE.equals(type);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java
new file mode 100644
index 0000000..6186382
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java
@@ -0,0 +1,130 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SubArrayVisitor extends AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element m_elem;
+
+ /**
+ * Attribute name.
+ */
+ private String m_name;
+
+ /**
+ * Attribute value.
+ * (accumulator)
+ */
+ private String m_acc;
+
+ /**
+ * Constructor.
+ *
+ * @param elem : element element.
+ * @param name : attribute name.
+ */
+ public SubArrayVisitor(Element elem, String name) {
+ super(Opcodes.ASM5);
+ m_elem = elem;
+ m_name = name;
+ }
+
+ /**
+ * Visit a 'simple' element of the visited array.
+ *
+ * @param name : null
+ * @param value : element value.
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (m_acc == null) {
+ if (!(value instanceof Type)) {
+ m_acc = "{" + value.toString();
+ } else {
+ // Attributes of type class need a special handling
+ m_acc = "{" + ((Type) value).getClassName();
+ }
+ } else {
+ if (!(value instanceof Type)) {
+ m_acc = m_acc + "," + value.toString();
+ } else {
+ // Attributes of type class need a special handling
+ m_acc = m_acc + "," + ((Type) value).getClassName();
+ }
+ }
+ }
+
+ /**
+ * Visits an enumeration attribute.
+ *
+ * @param name the attribute name
+ * @param desc the enumeration descriptor
+ * @param value the attribute value
+ */
+ public void visitEnum(String name, String desc, String value) {
+ if (m_acc == null) {
+ m_acc = "{" + value;
+ } else {
+ m_acc = m_acc + "," + value;
+ }
+ }
+
+
+ /**
+ * Visit an annotation element of the visited array.
+ *
+ * @param name : null
+ * @param desc : annotation to visit
+ * @return the visitor which will visit the annotation
+ * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ // Sub annotations are map to sub-elements
+ Element elem = Elements.buildElement(Type.getType(desc));
+ m_elem.addElement(elem);
+ return new GenericVisitor(elem);
+ }
+
+ /**
+ * End of the visit.
+ *
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_acc != null) {
+ // We have analyzed an attribute
+ m_elem.addAttribute(new Attribute(m_name, m_acc + "}"));
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java
new file mode 100644
index 0000000..9da0437
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TypeGenericVisitor extends RootGenericVisitor {
+ public TypeGenericVisitor(ComponentWorkbench workbench, Element element) {
+ super(workbench, element, ElementType.TYPE);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullBinding.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullBinding.java
new file mode 100644
index 0000000..b736d8b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullBinding.java
@@ -0,0 +1,40 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.ignore;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.alwaysTrue;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+import org.objectweb.asm.Type;
+
+/**
+ * User: guillaume
+ * Date: 10/07/13
+ * Time: 15:04
+ */
+public class NullBinding extends Binding {
+ public NullBinding(final Type type) {
+ super();
+ setAnnotationType(type);
+ setPredicate(alwaysTrue());
+ setFactory(NullVisitorFactory.INSTANCE);
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullVisitorFactory.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullVisitorFactory.java
new file mode 100644
index 0000000..c056e9e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ignore/NullVisitorFactory.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore;
+
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+* User: guillaume
+* Date: 10/07/13
+* Time: 15:05
+*/
+public class NullVisitorFactory implements AnnotationVisitorFactory {
+ public static final AnnotationVisitorFactory INSTANCE = new NullVisitorFactory();
+
+ public AnnotationVisitor newAnnotationVisitor(final BindingContext context) {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/FieldStereotypeVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/FieldStereotypeVisitor.java
new file mode 100644
index 0000000..e63debe
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/FieldStereotypeVisitor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.stereotype;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parses stereotypes for field.
+ */
+public class FieldStereotypeVisitor extends AnnotationVisitor {
+
+ private final FieldVisitor m_delegate;
+ private final AnnotationType m_annotationType;
+
+ public FieldStereotypeVisitor(final FieldVisitor delegate, AnnotationType annotationType) {
+ super(Opcodes.ASM5);
+ this.m_delegate = delegate;
+ m_annotationType = annotationType;
+ }
+
+ @Override
+ public void visitEnd() {
+ // Replay stereotype annotations
+ for (Playback playback : m_annotationType.getPlaybacks()) {
+ playback.accept(m_delegate);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/MethodStereotypeVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/MethodStereotypeVisitor.java
new file mode 100644
index 0000000..716eec2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/MethodStereotypeVisitor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.stereotype;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Parse stereotypes for methods.
+ */
+public class MethodStereotypeVisitor extends AnnotationVisitor {
+
+ private final MethodVisitor m_delegate;
+ private final AnnotationType m_annotationType;
+
+ public MethodStereotypeVisitor(final MethodVisitor delegate, AnnotationType annotationType) {
+ super(Opcodes.ASM5);
+ this.m_delegate = delegate;
+ m_annotationType = annotationType;
+ }
+
+ @Override
+ public void visitEnd() {
+ // Replay stereotype annotations
+ for (Playback playback : m_annotationType.getPlaybacks()) {
+ playback.accept(m_delegate);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/ParameterStereotypeVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/ParameterStereotypeVisitor.java
new file mode 100644
index 0000000..c766040
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/ParameterStereotypeVisitor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.stereotype;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * User: guillaume
+ * Date: 30/05/13
+ * Time: 18:55
+ */
+public class ParameterStereotypeVisitor extends AnnotationVisitor {
+
+ private final MethodVisitor m_delegate;
+ private final int index;
+ private final AnnotationType m_annotationType;
+
+ public ParameterStereotypeVisitor(final MethodVisitor delegate, final int index, AnnotationType annotationType) {
+ super(Opcodes.ASM5);
+ this.m_delegate = delegate;
+ this.index = index;
+ m_annotationType = annotationType;
+ }
+
+ @Override
+ public void visitEnd() {
+ // Replay stereotype annotations
+ for (Playback playback : m_annotationType.getPlaybacks()) {
+ playback.accept(m_delegate, index);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/StereotypeVisitorFactory.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/StereotypeVisitorFactory.java
new file mode 100644
index 0000000..b156f4d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/StereotypeVisitorFactory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.stereotype;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+* User: guillaume
+* Date: 11/07/13
+* Time: 14:26
+*/
+public class StereotypeVisitorFactory implements AnnotationVisitorFactory {
+ private final AnnotationType m_annotationType;
+
+ public StereotypeVisitorFactory(final AnnotationType annotationType) {
+ m_annotationType = annotationType;
+ }
+
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ if (context.getClassNode() != null) {
+ return new TypeStereotypeVisitor((ClassVisitor) context.getVisitor(),
+ m_annotationType);
+ } else if (context.getFieldNode() != null) {
+ return new FieldStereotypeVisitor((FieldVisitor) context.getVisitor(),
+ m_annotationType);
+
+ } else if ((context.getMethodNode() != null) &&
+ (context.getParameterIndex() == BindingContext.NO_INDEX)) {
+ return new MethodStereotypeVisitor((MethodVisitor) context.getVisitor(),
+ m_annotationType);
+
+ } else {
+ // last case: method parameter annotation
+ return new ParameterStereotypeVisitor((MethodVisitor) context.getVisitor(),
+ context.getParameterIndex(),
+ m_annotationType);
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "StereotypeVisitorFactory";
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/TypeStereotypeVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/TypeStereotypeVisitor.java
new file mode 100644
index 0000000..a2e9ee2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/stereotype/TypeStereotypeVisitor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.stereotype;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.Playback;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * User: guillaume
+ * Date: 30/05/13
+ * Time: 18:55
+ */
+public class TypeStereotypeVisitor extends AnnotationVisitor {
+
+ private final ClassVisitor m_delegate;
+ private final AnnotationType m_annotationType;
+
+ public TypeStereotypeVisitor(final ClassVisitor delegate, AnnotationType annotationType) {
+ super(Opcodes.ASM5);
+ this.m_delegate = delegate;
+ m_annotationType = annotationType;
+ }
+
+ @Override
+ public void visitEnd() {
+ // Replay stereotype annotations
+ for (Playback playback : m_annotationType.getPlaybacks()) {
+ playback.accept(m_delegate);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java
new file mode 100644
index 0000000..5da9928
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java
@@ -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.felix.ipojo.manipulator.metadata.annotation.visitor.util;
+
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.DefaultBindingRegistry;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.IgnoreAllBindingRegistry;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.LegacyGenericBindingRegistry;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.MetaAnnotationBindingRegistry;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Bindings {
+
+ public static BindingRegistry newBindingRegistry(final Reporter reporter,
+ final ResourceStore store,
+ final ModuleProvider provider) {
+
+ // Build the registry by aggregation of the features we want
+ // TODO We can enable/disable the legacy support easily here
+ BindingRegistry registry = new DefaultBindingRegistry(reporter);
+ registry = new MetaAnnotationBindingRegistry(registry, reporter, store);
+ registry = new LegacyGenericBindingRegistry(registry, reporter);
+ registry = new IgnoreAllBindingRegistry(registry, reporter);
+
+ // Build each Module and add its contributed Bindings in the registry
+ for (Module module : provider.findModules()) {
+ module.load();
+ registry.addBindings(module);
+ }
+
+ return registry;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java
new file mode 100644
index 0000000..f9c2cc1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java
@@ -0,0 +1,94 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.util;
+
+import static java.lang.String.format;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Elements {
+
+ /**
+ * Build the {@link Element} object from the given descriptor.
+ * It splits the annotation's classname in 2 parts (up to the last '.')
+ * first part (package's name) becomes the Element's namespace, and second
+ * part (class simple name) becomes the Element's name.
+ * @param type annotation descriptor
+ * @return the new element
+ */
+ public static Element buildElement(Type type) {
+ String name = type.getClassName();
+ int index = name.lastIndexOf('.');
+ String local = name.substring(index + 1);
+ String namespace = name.substring(0, index);
+ return buildElement(namespace, local);
+ }
+
+ /**
+ * Build an {@link Element} using the provided namespace and local name.
+ */
+ public static Element buildElement(final String namespace, final String name) {
+ return new Element(name, namespace);
+ }
+
+ /**
+ * Build an {@link Element} using the provided binding information.
+ * Expected format is {@literal [namespace:]name} (eg: {@literal com.acme:foo} or {@literal foo} if namespace
+ * by default -org.apache.felix.ipojo- has to be used).
+ * Notice that the ':' character usage in namespace or name part may lead to unexpected results.
+ * In that case, the @HandlerBinding(namespace = "urn:my:namespace", value = "foo:handler") usage is preferred.
+ * @param binding the condensed element name
+ * @return the new element
+ */
+ public static Element buildElement(String binding) {
+ String[] split = binding.split(":");
+ if (split.length == 1) {
+ return buildElement("", binding);
+ }
+ if (split.length > 2) {
+ throw new IllegalArgumentException(
+ format("@HandlerBinding(\"%s\") is invalid: only 1 ':' char is authorized, please" +
+ " use the @HandlerBinding(namespace=\"...\", value=\"...\") form instead.",
+ binding)
+ );
+ }
+ return buildElement(split[0], split[1]);
+ }
+
+ /**
+ * Return the Element named {@literal properties}, creates one if missing.
+ * @param workbench source for search
+ * @return the {@literal properties} Element (never null).
+ */
+ public static Element getPropertiesElement(ComponentWorkbench workbench) {
+ Element properties = workbench.getIds().get("properties");
+ if (properties == null) {
+ properties = buildElement("", "properties");
+ workbench.getIds().put("properties", properties);
+ workbench.getElements().put(properties, null);
+ }
+ return properties;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java
new file mode 100644
index 0000000..e8da6ff
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java
@@ -0,0 +1,136 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.ipojo.manipulation.ClassManipulator;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Names {
+
+ /**
+ * Excluded types when searching for a specification interface in method's arguments.
+ */
+ private static List<Type> EXCLUSIONS = new ArrayList<Type>();
+
+ static {
+ EXCLUSIONS.add(Type.getType(Map.class));
+ EXCLUSIONS.add(Type.getType(Dictionary.class));
+ EXCLUSIONS.add(Type.getType("Lorg/osgi/framework/ServiceReference;"));
+ }
+
+ /**
+ * Computes the real method name. This method is useful when the annotation is collected on an manipulated method
+ * (prefixed by <code>__M_</code>). This method just removes the prefix if found.
+ * @param name the collected method name
+ * @return the effective method name, can be the collected method name if the method name does not start with
+ * the prefix.
+ */
+ public static String computeEffectiveMethodName(String name) {
+ if (name != null && name.startsWith(ClassManipulator.PREFIX)) {
+ return name.substring(ClassManipulator.PREFIX.length());
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Extract an identifier from the given method name.
+ * It removes some pre-defined prefixes ({@literal bind}, {@literal unbind},
+ * {@literal set}, {@literal unset}, {@literal modified}).
+ *
+ * @param method method's name
+ * @return the method's identifier
+ */
+ public static String getMethodIdentifier(final MethodNode method) {
+
+ String effectiveName = computeEffectiveMethodName(method.name);
+
+ if (effectiveName.startsWith("bind")) {
+ return effectiveName.substring("bind".length());
+ }
+
+ if (effectiveName.startsWith("set")) {
+ return effectiveName.substring("set".length());
+ }
+
+ if (effectiveName.startsWith("unbind")) {
+ return effectiveName.substring("unbind".length());
+ }
+
+ if (effectiveName.startsWith("unset")) {
+ return effectiveName.substring("unset".length());
+ }
+
+ if (effectiveName.startsWith("modified")) {
+ return effectiveName.substring("modified".length());
+ }
+
+ if (effectiveName.startsWith("add")) {
+ return effectiveName.substring("add".length());
+ }
+
+ if (effectiveName.startsWith("remove")) {
+ return effectiveName.substring("remove".length());
+ }
+
+ // Try to discover the specification's type from method's parameters' type
+ Type[] arguments = Type.getArgumentTypes(method.desc);
+ return findSpecification(Arrays.asList(arguments));
+
+ }
+
+ /**
+ * Find the first type that was not excluded and consider it as the specification
+ * @param types method parameter's type
+ * @return the first non-excluded type or {@literal null} if no specification can be found
+ */
+ private static String findSpecification(final List<Type> types) {
+
+ // Find first non-excluded specification
+ // May return null if no specification is provided (likely a user error)
+ for (Type type : types) {
+ if (!EXCLUSIONS.contains(type)) {
+ return type.getClassName();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if the given annotation descriptor is an iPOJO custom annotation.
+ * A valid iPOJO custom annotation must contains 'ipojo' or 'handler' in its qualified name.
+ * @param desc annotation descriptor
+ * @return {@literal true} if the given descriptor is an iPOJO custom annotation
+ */
+ public static boolean isCustomAnnotation(final String desc) {
+ String lowerCase = desc.toLowerCase();
+ return lowerCase.contains("ipojo") || lowerCase.contains("handler");
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java
new file mode 100644
index 0000000..4b8fc3e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.manipulator.render;
+
+import org.apache.felix.ipojo.manipulation.ClassManipulator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code ManipulatedMetadataFilter}
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulatedMetadataFilter implements MetadataFilter {
+
+ public boolean accept(Element element) {
+
+ // TODO I'm sure we can do better then testing blindly all attributes
+ // iPOJO manipulated elements filter
+ for (Attribute attribute : element.getAttributes()) {
+ String value = attribute.getValue();
+
+ // Filters:
+ // * manipulated methods
+ // * fields for the InstanceManager
+ // * InstanceManager setter
+ if (value.startsWith(ClassManipulator.PREFIX)
+ || value.contains("org.apache.felix.ipojo.InstanceManager")
+ || value.contains("_setInstanceManager")) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java
new file mode 100644
index 0000000..1fe4fa5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.manipulator.render;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Defines a filter to be tested against Element before rendering them into the Manifest.
+ * If one filter accept the element, the given Element will be filtered, other filters will be ignored.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface MetadataFilter {
+
+ /**
+ * Tests if the given {@link Element} is accepted by the filter.
+ * @param element the tested element.
+ * @return {@literal true} if the filter accept the value (element will
+ * be omitted from the rendered metadata), {@literal false} otherwise.
+ */
+ public boolean accept(final Element element);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java
new file mode 100644
index 0000000..418ef21
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java
@@ -0,0 +1,140 @@
+/*
+ * 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.manipulator.render;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code MetadataRenderer} renders a given {@link Element} into a String.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MetadataRenderer {
+
+ private List<MetadataFilter> m_filters = new ArrayList<MetadataFilter>();
+
+ public MetadataRenderer() {
+ // By default, filter metadata coming from prior manipulation.
+ this.addMetadataFilter(new ManipulatedMetadataFilter());
+ }
+
+ /**
+ * Add a metadata filter
+ * @param filter added filter
+ */
+ public void addMetadataFilter(MetadataFilter filter) {
+ m_filters.add(filter);
+ }
+
+ /**
+ * Generate manipulation metadata.
+ * @param element rendered element.
+ * @return given manipulation metadata + manipulation metadata of the given element.
+ */
+ public String render(Element element) {
+ StringBuilder builder = new StringBuilder();
+ renderElement(element, builder);
+ return builder.toString();
+ }
+
+ private void renderElement(Element element, StringBuilder builder) {
+
+ // If the element is already here, do not re-add the element.
+ if(!isFiltered(element)) {
+
+ // Print the beginning of the element
+ startElement(element, builder);
+
+ // Render all attributes
+ for (Attribute attribute : element.getAttributes()) {
+ renderAttribute(attribute, builder);
+ }
+
+ // Render child elements
+ for (Element child : element.getElements()) {
+ renderElement(child, builder);
+ }
+
+ // Print the end of the element
+ endElement(builder);
+ }
+
+
+ }
+
+ private void startElement(Element element, StringBuilder builder) {
+ // Default namespace is empty
+ String namespace = "";
+ if (element.getNameSpace() != null) {
+ namespace = element.getNameSpace() + ":";
+ }
+
+ builder.append(namespace)
+ .append(element.getName())
+ .append(" { ");
+ }
+
+ private void endElement(StringBuilder builder) {
+ builder.append("}");
+ }
+
+ private void renderAttribute(Attribute current, StringBuilder builder) {
+
+ // Default namespace is empty
+ String namespace = "";
+ if (current.getNameSpace() != null) {
+ namespace = current.getNameSpace() + ":";
+ }
+
+ // Render the attribute
+ builder.append("$")
+ .append(namespace)
+ .append(current.getName())
+ .append("=")
+ .append(quoted(current.getValue()))
+ .append(" ");
+ }
+
+ private String quoted(String value) {
+ return "\"" + value + "\"";
+ }
+
+ /**
+ * Checks if the given element is an iPOJO generated element from a prior treatment
+ * @param element Element to be tested
+ * @return <code>true</code> if the given element was already injected by iPOJO
+ */
+ private boolean isFiltered(final Element element) {
+
+ // Iterates over all the filters and return the first positive answer (if any)
+ for (MetadataFilter filter : m_filters) {
+ if (filter.accept(element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java
new file mode 100644
index 0000000..28c4e03
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.manipulator.reporter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Collections5;
+
+/**
+ * An {@code EmptyReporter} is the basis implementation for Reporters.
+ * It is basically a no-op implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EmptyReporter implements Reporter {
+
+ /**
+ * List of warnings
+ */
+ private List<String> m_warnings = new ArrayList<String>();
+
+ /**
+ * List of errors
+ */
+ private List<String> m_errors = new ArrayList<String>();
+
+ public void trace(String message, Object... args) {}
+
+ public void info(String message, Object... args) {}
+
+ public void warn(String message, Object... args) {}
+
+ public void error(String message, Object... args) {}
+
+ public List<String> getErrors() {
+ return m_errors;
+ }
+
+ public List<String> getWarnings() {
+ return m_warnings;
+ }
+
+ protected Object[] getMessageArguments(Object... args) {
+ Object[] params = args;
+ if (args != null && args.length > 1) {
+ if (args[args.length - 1] instanceof Throwable) {
+ // last argument is an Exception, remove it
+ params = Collections5.copyOf(args, args.length - 1);
+ }
+ }
+
+ return params;
+ }
+
+ protected Throwable getThrowable(Object... args) {
+ Throwable throwable = null;
+ if (args != null && args.length > 1) {
+ if (args[args.length - 1] instanceof Throwable) {
+ // last argument is an Exception
+ throwable = (Throwable) args[args.length - 1];
+ }
+ }
+ return throwable;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java
new file mode 100644
index 0000000..0b1173e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java
@@ -0,0 +1,112 @@
+/*
+ * 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.manipulator.reporter;
+
+import java.io.PrintStream;
+
+/**
+ * A {@code SystemReporter} reports feedback from within the manipulation process.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SystemReporter extends EmptyReporter {
+
+ /**
+ * Micro enum used to prefix messages.
+ */
+ private enum Level {
+ TRACE("#"),
+ INFO("I"),
+ WARN("W"),
+ ERROR("E");
+
+ private String value;
+
+ Level(String value) {
+ this.value = value;
+ }
+
+ public String append(String message) {
+ return value + " " + message;
+ }
+ }
+
+ /**
+ * Enable/disable trace logging.
+ */
+ private boolean enableTrace = false;
+
+ public void setEnableTrace(boolean enableTrace) {
+ this.enableTrace = enableTrace;
+ }
+
+ private void log(PrintStream stream, Level level, String formatted, Throwable throwable) {
+ // Print the message
+ stream.println(level.append(formatted));
+
+ // And the exception if any
+ if (throwable != null) {
+ throwable.printStackTrace(stream);
+ }
+ }
+
+ @Override
+ public void trace(String message, Object... args) {
+ if (enableTrace) {
+ String formatted = String.format(message, getMessageArguments(args));
+ log(System.out, Level.TRACE, formatted, getThrowable());
+ }
+ }
+
+ @Override
+ public void info(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ log(System.out, Level.INFO, formatted, getThrowable());
+ }
+
+ @Override
+ public void warn(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable throwable = getThrowable();
+ log(System.out, Level.WARN, formatted, throwable);
+
+ // Append Exception message if any
+ if (throwable != null) {
+ formatted += " ";
+ formatted += throwable.getMessage();
+ }
+ getWarnings().add(formatted);
+ }
+
+ @Override
+ public void error(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable throwable = getThrowable();
+ log(System.out, Level.ERROR, formatted, throwable);
+
+ // Append Exception message if any
+ if (throwable != null) {
+ formatted += " ";
+ formatted += throwable.getMessage();
+ }
+ getErrors().add(formatted);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java
new file mode 100644
index 0000000..6f46672
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java
@@ -0,0 +1,212 @@
+/*
+ * 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.manipulator.spi;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.onlySupportedElements;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.AnnotationType;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.AnnotationPlayback;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.GenericVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.stereotype.StereotypeVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+
+/**
+ * All provided {@link Module}s have to inherit from this class.
+ * It provides a simple to use DSL to express annotation bindings.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbsBindingModule implements Module {
+
+ /**
+ * Build bindings.
+ */
+ private final List<Binding> bindings = new ArrayList<Binding>();
+
+ private boolean loaded = false;
+
+ public synchronized void load() {
+ if (!loaded) {
+ configure();
+ loaded = true;
+ }
+ }
+
+ /**
+ * Configure the bindings provided by this module.
+ */
+ protected abstract void configure();
+
+
+ public Iterator<Binding> iterator() {
+ return bindings.iterator();
+ }
+
+ /**
+ * Initiate an annotation binding.
+ * Examples:
+ * <pre>
+ * AnnotationVisitorFactory factory = new CompositeVisitorFactory();
+ * bind(Composite.class).to(factory);
+ * bind(Composite.class).when(.. some condition ..)
+ * .to(factory);
+ * </pre>
+ * @param annotationType the annotation that will be bound to the {@link AnnotationVisitorFactory}
+ */
+ protected AnnotationBindingBuilder bind(Class<? extends Annotation> annotationType) {
+ return new AnnotationBindingBuilder(bindings, annotationType);
+ }
+
+ protected StereotypeBindingBuilder bindStereotype(Class<? extends Annotation> annotationType) {
+ return new StereotypeBindingBuilder(bindings, annotationType);
+ }
+
+ protected HandlerBindingBuilder bindHandlerBinding(Class<? extends Annotation> annotationType) {
+ return new HandlerBindingBuilder(bindings, annotationType);
+ }
+
+ protected void bindIgnore(Class<? extends Annotation> annotationType) {
+ bindings.add(new NullBinding(Type.getType(annotationType)));
+ }
+
+ /**
+ * DSL helper class.
+ */
+ public class AnnotationBindingBuilder {
+ private Class<? extends Annotation> annotationType;
+ private AnnotationVisitorFactory factory;
+ private List<Binding> registry;
+
+ public AnnotationBindingBuilder(List<Binding> registry,
+ Class<? extends Annotation> annotationType) {
+ this.registry = registry;
+ this.annotationType = annotationType;
+ }
+
+ /**
+ * Declares a {@link Predicate} that will add a condition to the annotation binding.
+ * @see org.apache.felix.ipojo.manipulator.spi.helper.Predicates
+ * @param predicate the predicate to use
+ */
+ public ConditionalBindingBuilder when(Predicate predicate) {
+ return new ConditionalBindingBuilder(this, predicate);
+ }
+
+ /**
+ * Complete the annotation binding with the {@link AnnotationVisitorFactory} to be executed
+ * when the annotation is found.
+ * @param factory to be executed when the annotation is found.
+ */
+ public void to(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ registry.add(build());
+ }
+
+ /**
+ * Creates the Binding.
+ */
+ private Binding build() {
+ Binding binding = new Binding();
+ binding.setAnnotationType(Type.getType(annotationType));
+ binding.setPredicate(onlySupportedElements(annotationType));
+ binding.setFactory(factory);
+ return binding;
+ }
+
+ }
+
+ public class ConditionalBindingBuilder {
+ private AnnotationBindingBuilder parent;
+ private Predicate predicate;
+ private AnnotationVisitorFactory factory;
+
+ public ConditionalBindingBuilder(AnnotationBindingBuilder parent, Predicate predicate) {
+ this.parent = parent;
+ this.predicate = predicate;
+ }
+
+ /**
+ * Complete the annotation binding with the {@link AnnotationVisitorFactory} to be executed
+ * when the annotation is found.
+ * @param factory to be executed when the annotation is found.
+ */
+ public AnnotationBindingBuilder to(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ bindings.add(build());
+
+ return parent;
+ }
+
+ /**
+ * Creates the Binding.
+ */
+ private Binding build() {
+ Binding binding = parent.build();
+ binding.setPredicate(predicate);
+ binding.setFactory(factory);
+ return binding;
+ }
+ }
+
+ public class StereotypeBindingBuilder {
+ private final AnnotationType m_annotationType;
+
+ public StereotypeBindingBuilder(final List<Binding> bindings, final Class<? extends Annotation> type) {
+ m_annotationType = new AnnotationType(Type.getType(type));
+ Binding binding = new Binding();
+ binding.setAnnotationType(m_annotationType.getType());
+ binding.setPredicate(onlySupportedElements(type));
+ binding.setFactory(new StereotypeVisitorFactory(m_annotationType));
+ bindings.add(binding);
+ }
+
+ public StereotypeBindingBuilder with(AnnotationLiteral<?> literal) {
+ m_annotationType.getPlaybacks().add(new AnnotationPlayback(literal));
+ return this;
+ }
+ }
+
+ public class HandlerBindingBuilder {
+
+ private final Binding m_binding;
+
+ public HandlerBindingBuilder(final List<Binding> bindings, final Class<? extends Annotation> annotationType) {
+ m_binding = new Binding();
+ Type type = Type.getType(annotationType);
+ m_binding.setAnnotationType(type);
+ m_binding.setPredicate(onlySupportedElements(annotationType));
+ Element e = Elements.buildElement(type);
+ m_binding.setFactory(new GenericVisitorFactory(e.getName(), e.getNameSpace()));
+ bindings.add(m_binding);
+ }
+
+ public void to(String namespace, String name) {
+ m_binding.setFactory(new GenericVisitorFactory(name, namespace));
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteral.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteral.java
new file mode 100644
index 0000000..52ab4e4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteral.java
@@ -0,0 +1,84 @@
+/*
+ * 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.manipulator.spi;
+
+import static java.lang.String.format;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * Base annotation literal class to be extended when declaring stereotype bindings in a programmatic way.
+ * Usage example:
+ * <pre>
+ * public class InstantiateLiteral extends AnnotationLiteral<Instantiate> implements Instantiate {
+ * public String name() {
+ * return "";
+ * }
+ * }
+ * </pre>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AnnotationLiteral<T extends Annotation> implements Annotation {
+
+ private Class<? extends Annotation> annotationType;
+
+ public Class<? extends Annotation> annotationType() {
+ if (annotationType == null) {
+ annotationType = findAnnotationType(getClass());
+ if (annotationType == null) {
+ throw new IllegalStateException(
+ format("Annotation %s does not specify its annotation type (T) in AnnotationLiteral<T>",
+ getClass().getName())
+ );
+ }
+ }
+ return annotationType;
+ }
+
+ public org.objectweb.asm.Type getType() {
+ return org.objectweb.asm.Type.getType(annotationType());
+ }
+
+ private static Class<Annotation> findAnnotationType(final Class<? extends AnnotationLiteral> type) {
+ Class<?> implementer = findImplementer(type);
+ return findTypeParameter(implementer);
+ }
+
+ private static Class<Annotation> findTypeParameter(final Class<?> clazz) {
+ // Get the T of AnnotationLiteral<T>
+ Type type = clazz.getGenericSuperclass();
+ if (type instanceof ParameterizedType) {
+ ParameterizedType pType = (ParameterizedType) type;
+ return (Class<Annotation>) pType.getActualTypeArguments()[0];
+ }
+ return null;
+ }
+
+ private static Class<? extends AnnotationLiteral> findImplementer(final Class<? extends AnnotationLiteral> type) {
+ Class<? extends AnnotationLiteral> superClass = type.getSuperclass().asSubclass(AnnotationLiteral.class);
+ if (AnnotationLiteral.class.equals(superClass)) {
+ return type;
+ } else {
+ return findImplementer(superClass);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java
new file mode 100644
index 0000000..b29d3cc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java
@@ -0,0 +1,34 @@
+/*
+ * 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.manipulator.spi;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * Produces a new {@link AnnotationVisitor} instance for the given {@link BindingContext}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface AnnotationVisitorFactory {
+
+ /**
+ * May return {@literal null} if no visitor can be created.
+ */
+ AnnotationVisitor newAnnotationVisitor(BindingContext context);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java
new file mode 100644
index 0000000..4f57f17
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java
@@ -0,0 +1,162 @@
+/*
+ * 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.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BindingContext {
+
+ public static final int NO_INDEX = -1;
+
+ /**
+ *
+ */
+ private ComponentWorkbench workbench;
+ private FieldNode field;
+ private MethodNode method;
+ private ClassNode clazz;
+ private ElementType elementType;
+ private int parameterIndex;
+ private Reporter reporter;
+ private Type annotationType;
+ private Object visitor;
+
+
+ public BindingContext(final ComponentWorkbench workbench,
+ final Reporter reporter,
+ final Type annotationType,
+ final FieldNode node,
+ final ElementType elementType,
+ final int parameterIndex,
+ final Object visitor) {
+ this(workbench, reporter, annotationType, elementType, parameterIndex, visitor);
+ this.field = node;
+ }
+
+ public BindingContext(final ComponentWorkbench workbench,
+ final Reporter reporter,
+ final Type annotationType,
+ final MethodNode node,
+ final ElementType elementType,
+ final int parameterIndex,
+ final Object visitor) {
+ this(workbench, reporter, annotationType, elementType, parameterIndex, visitor);
+ this.method = node;
+ }
+
+ public BindingContext(final ComponentWorkbench workbench,
+ final Reporter reporter,
+ final Type annotationType,
+ final ClassNode node,
+ final ElementType elementType,
+ final int parameterIndex,
+ final Object visitor) {
+ this(workbench, reporter, annotationType, elementType, parameterIndex, visitor);
+ this.clazz = node;
+ }
+
+ private BindingContext(final ComponentWorkbench workbench,
+ final Reporter reporter,
+ final Type annotationType,
+ final ElementType elementType,
+ final int parameterIndex,
+ final Object visitor) {
+ this.workbench = workbench;
+ this.reporter = reporter;
+ this.annotationType = annotationType;
+ this.elementType = elementType;
+ this.parameterIndex = parameterIndex;
+ this.visitor = visitor;
+ }
+
+ public ComponentWorkbench getWorkbench() {
+ return workbench;
+ }
+
+ public FieldNode getFieldNode() {
+ return field;
+ }
+
+ public MethodNode getMethodNode() {
+ return method;
+ }
+
+ public ClassNode getClassNode() {
+ return clazz;
+ }
+
+ public ElementType getElementType() {
+ return elementType;
+ }
+
+ public int getParameterIndex() {
+ return parameterIndex;
+ }
+
+ public Reporter getReporter() {
+ return reporter;
+ }
+
+ public Type getAnnotationType() {
+ return annotationType;
+ }
+
+ public Object getVisitor() {
+ return visitor;
+ }
+
+ /**
+ * This method is just to support the compatibility with the previous version. It returns an ASM node of the
+ * member on which the annotation is 'attached'. The type of the node depends on this element. It can be a {@link
+ * org.objectweb.asm.tree.FieldNode}, a {@link org.objectweb.asm.tree.MethodNode} or a
+ * {@link org.objectweb.asm.tree.ClassNode}. It actually checks the current node and returns the first set ones
+ * in this order: field, method, class.
+ * <p/>
+ * The type of the returned object can be determined using the {@link #getElementType} method. However it is
+ * recommended to use one of the following method: {@link #getFieldNode()}, {@link #getMethodNode()} or
+ * {@link #getClassNode()}.
+ *
+ * @return the node.
+ * @deprecated
+ */
+ public Object getNode() {
+ if (field != null) {
+ return field;
+ }
+ if (method != null) {
+ return method;
+ }
+ if (clazz != null) {
+ return clazz;
+ }
+ // No node ?
+ return null;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java
new file mode 100644
index 0000000..3a2d00b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java
@@ -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.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+
+/**
+ * A Module is the contributions from third party to the iPOJO manipulation process.
+ * It is dedicated to Annotation binding support (executing a given ASM AnnotationVisitor
+ * when a particular annotation is found).
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Module extends Iterable<Binding> {
+
+ /**
+ * Load the bindings provided by this module (only once).
+ * @since 1.11.2
+ */
+ void load();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/ModuleProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/ModuleProvider.java
new file mode 100644
index 0000000..2eae682
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/ModuleProvider.java
@@ -0,0 +1,38 @@
+/*
+ * 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.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.spi.Module;
+
+/**
+ * Discover {@link org.apache.felix.ipojo.manipulator.spi.Module}s available in the "environment".
+ * Environment is dependent of the implementation.
+ * @since 1.11.2
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ModuleProvider {
+
+ /**
+ * Discover a set of modules at a given time.
+ * Returned modules could disappear in the future.
+ * @return discovered modules (should <bold>NEVER</bold> returns {@literal null})
+ */
+ Iterable<Module> findModules();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java
new file mode 100644
index 0000000..cee734b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java
@@ -0,0 +1,39 @@
+/*
+ * 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.manipulator.spi;
+
+/**
+ * A Predicate is executed with a given {@link BindingContext} and returns {@literal true} if the
+ * {@link #matches(BindingContext)} operation is a success. It returns {@literal false} otherwise.
+ * Predicates can be used to determine if the traversed element (can be found on {@link BindingContext})
+ * matches some properties.
+ *
+ * @see org.apache.felix.ipojo.manipulator.spi.helper.Predicates
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Predicate {
+
+ /**
+ * Returns {@literal true} if the context is matching the predicate.
+ * @param context Binding information source
+ * @return {@literal true} if the context is matching the predicate, {@literal false} otherwise.
+ */
+ boolean matches(BindingContext context);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java
new file mode 100644
index 0000000..1c9c462
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java
@@ -0,0 +1,224 @@
+/*
+ * 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.manipulator.spi.helper;
+
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.regex.Pattern;
+
+/**
+ * Ready-to-use {@link Predicate} implementations.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Predicates {
+ public static Node node() {
+ return new Node();
+ }
+
+ public static Reference reference(String refId) {
+ return new Reference(refId);
+ }
+
+ public static Matcher pattern(String regex) {
+ return new Matcher(regex);
+ }
+
+ /**
+ * Restrict to the given {@link ElementType}.
+ * @param type expected {@link ElementType}
+ */
+ public static Predicate on(final ElementType type) {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return context.getElementType().equals(type);
+ }
+ };
+ }
+
+ /**
+ * Always return {@literal true}.
+ */
+ public static Predicate alwaysTrue() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Successful if all given predicates are satisfied.
+ * @param predicates predicates to be satisfied
+ */
+ public static Predicate and(final Predicate... predicates) {
+
+ // Optimization
+ if (predicates.length == 1) {
+ return predicates[0];
+ }
+
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+
+ for (Predicate predicate : predicates) {
+ // Quit with first failure
+ if (!predicate.matches(context)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Successful if at least one of the given predicates is satisfied.
+ * @param predicates predicates to be satisfied (at least one)
+ */
+ public static Predicate or(final Collection<Predicate> predicates) {
+
+ // Optimization
+ if (predicates.size() == 1) {
+ return predicates.iterator().next();
+ }
+
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+
+ for (Predicate predicate : predicates) {
+ // Quit with first success
+ if (predicate.matches(context)) {
+ return true;
+ }
+ }
+ // No predicate were matching
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Successful if at least one of the given predicates is satisfied.
+ * @param predicates predicates to be satisfied (at least one)
+ */
+ public static Predicate or(final Predicate... predicates) {
+ return or(Arrays.asList(predicates));
+ }
+
+ /**
+ * Restrict to the supported {@link ElementType}(s) of the annotation (use the @Target, if provided).
+ * @param annotationType annotation to explore
+ */
+ public static Predicate onlySupportedElements(final Class<? extends Annotation> annotationType) {
+ Target target = annotationType.getAnnotation(Target.class);
+ if (target == null) {
+ return alwaysTrue();
+ }
+
+ Collection<Predicate> supportedTypes = new HashSet<Predicate>();
+ for (ElementType type : target.value()) {
+ supportedTypes.add(on(type));
+ }
+
+ return or(supportedTypes);
+ }
+
+ public static class Reference {
+
+ private String refId;
+
+ public Reference(String refId) {
+ this.refId = refId;
+ }
+
+ /**
+ * Restrict execution if the {@link org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench}
+ * contains the given reference's name.
+ */
+ public Predicate exists() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return context.getWorkbench().getIds().containsKey(refId);
+ }
+ };
+ }
+ }
+
+ public static class Matcher {
+
+ private Pattern pattern;
+
+ public Matcher(String regex) {
+ pattern = Pattern.compile(regex);
+ }
+
+ /**
+ * Restrict execution if the annotation's classname matches the given pattern.
+ */
+ public Predicate matches() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return pattern.matcher(context.getAnnotationType().getClassName()).matches();
+ }
+ };
+ }
+ }
+
+ public static class Node {
+ /**
+ * Restrict execution if the supported {@literal Node} has the given name.
+ */
+ public Predicate named(final String expected) {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ if (context.getFieldNode() != null) {
+ FieldNode field = context.getFieldNode();
+ return field.name.equals(expected);
+ }
+
+ if (context.getMethodNode() != null) {
+ MethodNode method = context.getMethodNode();
+ return method.name.equals(expected);
+ }
+
+ if (context.getClassNode() != null) {
+ ClassNode clazz = context.getClassNode();
+ return clazz.name.equals(expected);
+ }
+
+ // Parameters have no name in bytecode
+
+ return false;
+ }
+ };
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CompositeModuleProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CompositeModuleProvider.java
new file mode 100644
index 0000000..2e62514
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CompositeModuleProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.manipulator.spi.provider;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+
+/**
+ * Encapsulate other ModuleProviders in a single instance.
+ * @since 1.11.2
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeModuleProvider implements ModuleProvider {
+
+ private final Iterable<ModuleProvider> providers;
+
+ public CompositeModuleProvider(ModuleProvider... providers) {
+ this(Arrays.asList(providers));
+ }
+
+ public CompositeModuleProvider(final Iterable<ModuleProvider> providers) {
+ this.providers = providers;
+ }
+
+ public Iterable<Module> findModules() {
+ List<Module> modules = new ArrayList<Module>();
+ for (ModuleProvider provider : providers) {
+ for (Module module : provider.findModules()) {
+ modules.add(module);
+ }
+ }
+ return modules;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CoreModuleProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CoreModuleProvider.java
new file mode 100644
index 0000000..0bfca28
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/CoreModuleProvider.java
@@ -0,0 +1,33 @@
+/*
+ * 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.manipulator.spi.provider;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.module.DefaultBindingModule;
+
+/**
+ * Hardcoded provider for default core manipulation module.
+ * @since 1.11.2
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CoreModuleProvider extends DefaultModuleProvider {
+ public CoreModuleProvider() {
+ super(new DefaultBindingModule());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/DefaultModuleProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/DefaultModuleProvider.java
new file mode 100644
index 0000000..863d97d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/DefaultModuleProvider.java
@@ -0,0 +1,53 @@
+/*
+ * 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.manipulator.spi.provider;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+
+/**
+ * Return the given collection of {@link org.apache.felix.ipojo.manipulator.spi.Module}s.
+ * @since 1.11.2
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultModuleProvider implements ModuleProvider {
+
+ private final Iterable<Module> modules;
+
+ public DefaultModuleProvider() {
+ this(Collections.<Module>emptyList());
+ }
+
+ public DefaultModuleProvider(Module... modules) {
+ this(Arrays.asList(modules));
+ }
+
+ public DefaultModuleProvider(final Iterable<Module> modules) {
+ this.modules = modules;
+ }
+
+ public Iterable<Module> findModules() {
+ return modules;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/ServiceLoaderModuleProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/ServiceLoaderModuleProvider.java
new file mode 100644
index 0000000..50b2456
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/provider/ServiceLoaderModuleProvider.java
@@ -0,0 +1,52 @@
+/*
+ * 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.manipulator.spi.provider;
+
+import java.util.ServiceLoader;
+
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+
+/**
+ * Find {@link org.apache.felix.ipojo.manipulator.spi.Module}s using the {@link java.util.ServiceLoader} mechanisms.
+ * @since 1.11.2
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceLoaderModuleProvider implements ModuleProvider {
+
+ private final ClassLoader loader;
+
+ public ServiceLoaderModuleProvider() {
+ this(ServiceLoaderModuleProvider.class);
+ }
+
+ public ServiceLoaderModuleProvider(final Class<?> type) {
+ this(type.getClassLoader());
+ }
+
+ public ServiceLoaderModuleProvider(ClassLoader loader) {
+ this.loader = loader;
+ }
+
+ public Iterable<Module> findModules() {
+ return ServiceLoader.load(Module.class, loader);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
new file mode 100644
index 0000000..b0f3ce1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
@@ -0,0 +1,170 @@
+/*
+ * 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.manipulator.store;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.store.mapper.FileSystemResourceMapper;
+import org.apache.felix.ipojo.manipulator.store.mapper.IdentityResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@link DirectoryResourceStore} knows how to read and write
+ * resources from (to respectively) a File directory.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DirectoryResourceStore implements ResourceStore {
+
+ /**
+ * Source directory where bytecode is read.
+ */
+ private File m_source;
+
+ /**
+ * Target directory.
+ */
+ private File m_target;
+
+ /**
+ * The builder of the updated manifest.
+ */
+ private ManifestBuilder m_manifestBuilder;
+
+ /**
+ * Original manifest to be updated.
+ */
+ private Manifest m_manifest;
+
+ /**
+ * Location of the manifest file to update.
+ */
+ private File m_manifest_file;
+
+ /**
+ * Resource Mapper.
+ */
+ private ResourceMapper m_mapper = new FileSystemResourceMapper(new IdentityResourceMapper());
+
+ public DirectoryResourceStore(File source) {
+ this(source, source);
+ }
+
+ public DirectoryResourceStore(File source, File target) {
+ m_source = source;
+ m_target = target;
+ }
+
+ public void setResourceMapper(ResourceMapper mapper) {
+ m_mapper = new FileSystemResourceMapper(mapper);
+ }
+
+ public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+ m_manifestBuilder = manifestBuilder;
+ }
+
+ public void setManifest(Manifest manifest) {
+ m_manifest = manifest;
+ }
+
+ public void setManifestFile(File manifestFile){
+ m_manifest_file = manifestFile;
+ }
+
+ public byte[] read(String path) throws IOException {
+ File resource = new File(m_source, m_mapper.internalize(path));
+ if (!resource.isFile()) {
+ throw new IOException("File '" + resource + "' is not found (for class " + path + ").");
+ }
+ return Streams.readBytes(new FileInputStream(resource));
+ }
+
+ public void accept(ResourceVisitor visitor) {
+ traverseDirectory(m_source, visitor);
+ }
+
+ private void traverseDirectory(File directory, ResourceVisitor visitor) {
+ for (File child : directory.listFiles()) {
+ if (child.isDirectory()) {
+ traverseDirectory(child, visitor);
+ } else {
+ visitor.visit(getRelativeName(child));
+ }
+ }
+ }
+
+ private String getRelativeName(File file) {
+ String relative = file.getPath().substring(m_source.getPath().length());
+ return m_mapper.externalize(relative);
+ }
+
+ public void open() throws IOException {
+
+ // Update the manifest
+ Manifest updated = m_manifestBuilder.build(m_manifest);
+
+ // Write it to disk
+ OutputStream os = new FileOutputStream(m_manifest_file);
+ try {
+ updated.write(os);
+ } finally {
+ Streams.close(os);
+ }
+
+ }
+
+ public void writeMetadata(Element metadata) {
+ m_manifestBuilder.addMetada(Collections.singletonList(metadata));
+ m_manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+ }
+
+ public void write(String resourcePath, byte[] bytecode) throws IOException {
+
+ // Internalize the name
+ File resource = new File(m_target, m_mapper.internalize(resourcePath));
+
+ // Create intermediate directories if needed
+ if (!resource.getParentFile().exists()) {
+ resource.getParentFile().mkdirs();
+ }
+
+ FileOutputStream fos = new FileOutputStream(resource);
+ try {
+ fos.write(bytecode);
+ fos.flush();
+ } finally {
+ Streams.close(fos);
+ }
+ }
+
+ public void close() throws IOException {
+ // Nothing to do
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java
new file mode 100644
index 0000000..44d185a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java
@@ -0,0 +1,250 @@
+/*
+ * 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.manipulator.store;
+
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.store.mapper.IdentityResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.*;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+/**
+ * A {@link JarFileResourceStore} knows how to read and write
+ * resources from (to respectively) a Jar File.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JarFileResourceStore implements ResourceStore {
+
+ /**
+ * Source Jar.
+ */
+ private JarFile m_source;
+
+ /**
+ * Target File.
+ */
+ private File m_target;
+
+ /**
+ * Modified resources.
+ */
+ private Map<String, byte[]> m_content;
+
+ /**
+ * Resource Mapper.
+ */
+ private ResourceMapper m_mapper = new IdentityResourceMapper();
+
+ /**
+ * The builder of the updated manifest.
+ */
+ private ManifestBuilder m_manifestBuilder;
+
+ /**
+ * Original manifest to be updated.
+ */
+ private Manifest m_manifest;
+
+ private ClassLoader classLoader;
+
+ /**
+ * Construct a {@link JarFileResourceStore} wrapping the given original bundle,
+ * and configured to output in the given target file.
+ *
+ * @param source original Bundle
+ * @param target File where the updated Bundle will be outputted
+ * @throws IOException if there is an error retrieving the Manifest from the original JarFile
+ */
+ public JarFileResourceStore(JarFile source, File target) throws IOException {
+ m_source = source;
+ m_target = target;
+
+ // TODO ensure File is not null and not an existing file/directory
+ this.m_target = target;
+ if (source != null) {
+ m_manifest = source.getManifest();
+ } else {
+ m_manifest = new Manifest();
+ }
+ m_content = new TreeMap<String, byte[]>();
+ }
+
+ public void setResourceMapper(ResourceMapper mapper) {
+ this.m_mapper = mapper;
+ }
+
+ public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+ this.m_manifestBuilder = manifestBuilder;
+ }
+
+ public void setManifest(Manifest manifest) {
+ this.m_manifest = manifest;
+ }
+
+ public void setClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ public byte[] read(String path) throws IOException {
+ ZipEntry entry = m_source.getEntry(getInternalPath(path));
+ if (entry == null) {
+ // Not in the Jar file, trying from classpath
+ return tryToLoadFromClassloader(path);
+ }
+ return Streams.readBytes(m_source.getInputStream(entry));
+ }
+
+ private byte[] tryToLoadFromClassloader(String path) throws IOException {
+ if (classLoader != null) {
+ byte[] bytes = toByteArray(classLoader.getResource(path));
+ if (bytes != null) {
+ return bytes;
+ }
+ }
+ throw new IOException("Class not found " + path + ".");
+ }
+
+ public static byte[] toByteArray(URL url) throws IOException {
+ if (url == null) {
+ return null;
+ }
+ InputStream input = url.openStream();
+ try {
+ return Streams.readBytes(input);
+ } finally {
+ Streams.close(input);
+ }
+
+ }
+
+ private String getInternalPath(String path) {
+ return m_mapper.internalize(path);
+ }
+
+ public void accept(ResourceVisitor visitor) {
+ List<JarEntry> entries = Collections.list(m_source.entries());
+ for (JarEntry entry : entries) {
+ String name = entry.getName();
+ if (!name.endsWith("/")) {
+ // Do not visit directories
+ visitor.visit(getExternalName(entry.getName()));
+ }
+ }
+ }
+
+ private String getExternalName(String path) {
+ return m_mapper.externalize(path);
+ }
+
+ public void open() throws IOException {
+ // Nothing to do
+ }
+
+ public void writeMetadata(Element metadata) {
+ m_manifestBuilder.addMetada(Collections.singletonList(metadata));
+ m_manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+ }
+
+ public void write(String resourcePath, byte[] resource) throws IOException {
+ this.m_content.put(getInternalPath(resourcePath), resource);
+ }
+
+ public void close() throws IOException {
+
+ // Update the manifest
+ Manifest updated = m_manifestBuilder.build(m_manifest);
+
+ // Create a new Jar file
+ FileOutputStream fos = new FileOutputStream(m_target);
+ JarOutputStream jos = new JarOutputStream(fos, updated);
+
+ try {
+ // Copy classes and resources
+ List<JarEntry> entries = Collections.list(m_source.entries());
+ for (JarEntry entry : entries) {
+
+ // Ignore some entries (MANIFEST, ...)
+ if (isIgnored(entry)) {
+ continue;
+ }
+
+ if (isUpdated(entry)) {
+ // Write newer/updated resource (manipulated classes, ...)
+
+ JarEntry je = new JarEntry(entry.getName());
+ byte[] data = m_content.get(getInternalPath(entry.getName()));
+ jos.putNextEntry(je);
+ jos.write(data);
+ jos.closeEntry();
+ } else {
+ // Copy the resource as-is
+
+ jos.putNextEntry(entry);
+ InputStream is = m_source.getInputStream(entry);
+ try {
+ Streams.transfer(is, jos);
+ } finally {
+ Streams.close(is);
+ }
+
+ jos.closeEntry();
+
+ }
+ }
+ } finally {
+ try {
+ m_source.close();
+ } catch (IOException e) {
+ // Ignored
+ }
+ Streams.close(jos, fos);
+
+ }
+ }
+
+ private boolean isUpdated(JarEntry entry) {
+ // Check if that class was manipulated
+ if (entry.getName().endsWith(".class")) {
+ // Need to map this into an external+normalized path
+ String cleaned = getExternalName(entry.getName());
+ return m_content.containsKey(cleaned);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isIgnored(JarEntry entry) {
+ return "META-INF/MANIFEST.MF".equals(entry.getName());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java
new file mode 100644
index 0000000..a3b1026
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * 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.manipulator.store;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code ManifestBuilder} is ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestBuilder {
+ /**
+ * Add all given package names in the referred packages list
+ * @param packageNames additional packages
+ */
+ void addReferredPackage(Set<String> packageNames);
+
+ /**
+ * Add all given metadata
+ * @param metadatas additional metadata
+ */
+ void addMetada(Collection<Element> metadatas);
+
+ /**
+ * Update the given manifest.
+ * @param original original manifest to be modified
+ * @return modified manifest
+ */
+ Manifest build(Manifest original);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java
new file mode 100644
index 0000000..e5fe0fc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java
@@ -0,0 +1,43 @@
+/*
+ * 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.manipulator.store;
+
+/**
+ * A {@code ResourceMapper} maps resource name from a reference to another one.
+ * Example: In a WAB, class names are to be mapped into {@literal WEB-INF/classes/}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceMapper {
+
+ /**
+ * Adapts the normalized resource name into internal format.
+ * @param name original class names (as a resource)
+ * @return the transformed resource's name
+ */
+ String internalize(String name);
+
+ /**
+ * Provides a normalized resource name from the store's internal format.
+ * @param name resource name in internal format
+ * @return normalized resource name
+ */
+ String externalize(String name);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java
new file mode 100644
index 0000000..69be33a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java
@@ -0,0 +1,262 @@
+/*
+ * 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.manipulator.store.builder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.QuotedTokenizer;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.store.ManifestBuilder;
+import org.apache.felix.ipojo.manipulator.util.Constants;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code DefaultManifestBuilder} handles the knowledge of iPOJO Manifest building.
+ * It is responsible to update a given Manifest with all gathered (additional)
+ * referenced packages (from the metadata.xml) + other iPOJO specific additions.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultManifestBuilder implements ManifestBuilder {
+
+ /**
+ * Referenced packages (by the composites).
+ */
+ private List<String> m_referredPackages = new ArrayList<String>();
+
+ /**
+ * Computed metadatas from the bundle (XML files + annotations).
+ */
+ private List<Element> m_metadata = new ArrayList<Element>();
+
+ /**
+ * The metadata renderer used to print Elements.
+ */
+ private MetadataRenderer m_renderer;
+
+ /**
+ * Add all given package names in the referred packages list
+ * @param packageNames additional packages
+ */
+ public void addReferredPackage(Set<String> packageNames) {
+ m_referredPackages.addAll(packageNames);
+ }
+
+ /**
+ * Add all given metadata
+ * @param metadatas additional metadata
+ */
+ public void addMetada(Collection<Element> metadatas) {
+ m_metadata.addAll(metadatas);
+ }
+
+ public void setMetadataRenderer(MetadataRenderer renderer) {
+ m_renderer = renderer;
+ }
+
+ /**
+ * Update the given manifest.
+ * @param original original manifest to be modified
+ * @return modified manifest
+ */
+ public Manifest build(final Manifest original) {
+ Attributes att = original.getMainAttributes();
+
+ // Set the imports (add ipojo and handler namespaces
+ setImports(att);
+ // Add iPOJO-Component
+ setPOJOMetadata(att);
+ // Add iPOJO to the creators
+ setCreatedBy(att);
+
+ return original;
+ }
+
+ /**
+ * Add imports to the given manifest attribute list. This method add ipojo imports and handler imports (if needed).
+ * @param att : the manifest attribute list to modify.
+ */
+ private void setImports(Attributes att) {
+ Map<String, Map<String, String>> imports = parseHeader(att.getValue("Import-Package"));
+ Map<String, String> ver = new TreeMap<String, String>();
+ ver.put("version", Constants.getPackageImportClause());
+ if (!imports.containsKey("org.apache.felix.ipojo")) {
+ imports.put("org.apache.felix.ipojo", ver);
+ }
+ if (!imports.containsKey("org.apache.felix.ipojo.architecture")) {
+ imports.put("org.apache.felix.ipojo.architecture", ver);
+ }
+ if (!imports.containsKey("org.osgi.service.cm")) {
+ Map<String, String> verCM = new TreeMap<String, String>();
+ verCM.put("version", "1.2");
+ imports.put("org.osgi.service.cm", verCM);
+ }
+ if (!imports.containsKey("org.osgi.service.log")) {
+ Map<String, String> verCM = new TreeMap<String, String>();
+ verCM.put("version", "1.3");
+ imports.put("org.osgi.service.log", verCM);
+ }
+
+ // Add referred imports from the metadata
+ for (int i = 0; i < m_referredPackages.size(); i++) {
+ String pack = m_referredPackages.get(i);
+ imports.put(pack, new TreeMap<String, String>());
+ }
+
+ // Write imports
+ att.putValue("Import-Package", printClauses(imports, "resolution:"));
+ }
+
+ /**
+ * Add iPOJO-Components to the given manifest attribute list. This method add the
+ * {@literal iPOJO-Components} header and its value (according to the metadata)
+ * to the manifest.
+ * @param att the manifest attribute list to modify.
+ */
+ private void setPOJOMetadata(Attributes att) {
+ StringBuilder meta = new StringBuilder();
+ for (Element metadata : m_metadata) {
+ meta.append(m_renderer.render(metadata));
+ }
+ if (meta.length() != 0) {
+ att.putValue("iPOJO-Components", meta.toString());
+ }
+ }
+
+ /**
+ * Set the create-by in the manifest.
+ * @param att : manifest attribute.
+ */
+ private void setCreatedBy(Attributes att) {
+ String prev = att.getValue("Created-By");
+ if (prev == null) {
+ att.putValue("Created-By", "iPOJO " + Constants.getVersion());
+ } else {
+ if (prev.indexOf("iPOJO") == -1) {
+ // Avoid appending iPOJO several times
+ att.putValue("Created-By", prev + " & iPOJO " + Constants.getVersion());
+ }
+ }
+ }
+
+ /**
+ * Standard OSGi header parser. This parser can handle the format
+ * <pre>
+ * clauses ::= clause ( ',' clause ) +
+ * clause ::= name ( ';' name ) (';' key '=' value )
+ * </pre>
+ * This is mapped to a Map { name => Map { attr|directive => value } }
+ *
+ * @param value String to parse.
+ * @return parsed map.
+ */
+ protected Map<String, Map<String, String>> parseHeader(String value) {
+ if (value == null || value.trim().length() == 0) {
+ return new HashMap<String, Map<String, String>>();
+ }
+
+ Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+ QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
+ char del;
+ do {
+ boolean hadAttribute = false;
+ Map<String, String> clause = new HashMap<String, String>();
+ List<String> aliases = new ArrayList<String>();
+ aliases.add(qt.nextToken());
+ del = qt.getSeparator();
+ while (del == ';') {
+ String adname = qt.nextToken();
+ if ((del = qt.getSeparator()) != '=') {
+ if (hadAttribute) {
+ throw new IllegalArgumentException("Header contains name field after attribute or directive: " + adname + " from " + value);
+ }
+ aliases.add(adname);
+ } else {
+ String advalue = qt.nextToken();
+ clause.put(adname, advalue);
+ del = qt.getSeparator();
+ hadAttribute = true;
+ }
+ }
+ for (Iterator<String> i = aliases.iterator(); i.hasNext();) {
+ result.put(i.next(), clause);
+ }
+ } while (del == ',');
+ return result;
+ }
+
+ /**
+ * Print a standard Map based OSGi header.
+ *
+ * @param exports : map { name => Map { attribute|directive => value } }
+ * @param allowedDirectives list of allowed directives.
+ * @return the clauses
+ */
+ private String printClauses(Map<String, Map<String, String>> exports, String allowedDirectives) {
+ StringBuffer sb = new StringBuffer();
+ String del = "";
+
+ for (Iterator i = exports.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String name = (String) entry.getKey();
+ Map map = (Map) entry.getValue();
+ sb.append(del);
+ sb.append(name);
+
+ for (Iterator j = map.entrySet().iterator(); j.hasNext();) {
+ Map.Entry entry2 = (Map.Entry) j.next();
+ String key = (String) entry2.getKey();
+
+ // Skip directives we do not recognize
+ if (key.endsWith(":") && allowedDirectives.indexOf(key) < 0) {
+ continue;
+ }
+
+ String value = (String) entry2.getValue();
+ sb.append(";");
+ sb.append(key);
+ sb.append("=");
+ boolean dirty = value.indexOf(',') >= 0 || value.indexOf(';') >= 0;
+ if (dirty) {
+ sb.append("\"");
+ }
+ sb.append(value);
+ if (dirty) {
+ sb.append("\"");
+ }
+ }
+ del = ", ";
+ }
+ return sb.toString();
+ }
+
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
new file mode 100644
index 0000000..9f7f3dc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.manipulator.store.mapper;
+
+import java.io.File;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * ResourceMapper mapping from and to system specific path..
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileSystemResourceMapper implements ResourceMapper {
+
+ private ResourceMapper m_delegate;
+ private char m_separator;
+
+ public FileSystemResourceMapper(ResourceMapper delegate) {
+ this(delegate, File.separatorChar);
+ }
+
+ public FileSystemResourceMapper(ResourceMapper delegate, char separator) {
+ m_delegate = delegate;
+ m_separator = separator;
+ }
+
+ public String internalize(String name) {
+ // transform as system path the result of the internalization operation
+ return systemPath(m_delegate.internalize(name));
+ }
+
+ public String externalize(String name) {
+ // normalize he path before giving it to the delegate mapper
+ return m_delegate.externalize(normalizePath(name));
+ }
+
+ /**
+ * Normalize the given path. Normalization simply replace any
+ * File separator (system dependant) with {@literal '/'}.
+ * @param path system path
+ * @return normalized path
+ */
+ private String normalizePath(String path) {
+ return path.replace(m_separator, '/');
+ }
+
+ /**
+ * Return a system path from the given normalized path.
+ * @param path normalized path
+ * @return system path
+ */
+ private String systemPath(String path) {
+ return path.replace('/', m_separator);
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java
new file mode 100644
index 0000000..ab454fd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java
@@ -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.manipulator.store.mapper;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * Identity mapper.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IdentityResourceMapper implements ResourceMapper {
+ public String internalize(String name) {
+ return name;
+ }
+
+ public String externalize(String name) {
+ return name;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java
new file mode 100644
index 0000000..c73b235
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java
@@ -0,0 +1,58 @@
+/*
+ * 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.manipulator.store.mapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * A {@code WABResourceMapper} knows how to map resource names for a Web Application Bundle (WAB).
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class WABResourceMapper implements ResourceMapper {
+
+ public static final String WEB_INF_CLASSES = "WEB-INF/classes/";
+
+ /**
+ * Store externalized names so that internalize can rebuild the good resource name.
+ */
+ private List<String> mappedNames = new ArrayList<String>();
+
+ public String internalize(String name) {
+ if (mappedNames.contains(name)) {
+ return WEB_INF_CLASSES + name;
+ }
+ return name;
+ }
+
+ public String externalize(String name) {
+ if (name.startsWith(WEB_INF_CLASSES)) {
+ String externalized = name.substring(WEB_INF_CLASSES.length());
+ mappedNames.add(externalized);
+ return externalized;
+ }
+ // Leave the name unchanged
+ // (it's probably META-INF/** or WEB-INF/lib/**)
+ return name;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/ChainedAnnotationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/ChainedAnnotationVisitor.java
new file mode 100644
index 0000000..f7da4e0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/ChainedAnnotationVisitor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.manipulator.util;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* User: guillaume
+* Date: 10/07/13
+* Time: 16:43
+*/
+public class ChainedAnnotationVisitor extends AnnotationVisitor {
+
+ private List<AnnotationVisitor> m_visitors = new ArrayList<AnnotationVisitor>();
+
+ public ChainedAnnotationVisitor() {
+ super(Opcodes.ASM5);
+ }
+
+ public List<AnnotationVisitor> getVisitors() {
+ return m_visitors;
+ }
+
+ public void visit(final String name, final Object value) {
+ for (AnnotationVisitor visitor : m_visitors) {
+ visitor.visit(name, value);
+ }
+ }
+
+ public void visitEnum(final String name, final String desc, final String value) {
+ for (AnnotationVisitor visitor : m_visitors) {
+ visitor.visitEnum(name, desc, value);
+ }
+ }
+
+ public AnnotationVisitor visitAnnotation(final String name, final String desc) {
+ ChainedAnnotationVisitor chain = null;
+ for (AnnotationVisitor visitor : m_visitors) {
+ AnnotationVisitor child = visitor.visitAnnotation(name, desc);
+ if (child != null) {
+ if (chain == null) {
+ chain = new ChainedAnnotationVisitor();
+ }
+ chain.getVisitors().add(child);
+ }
+
+ }
+ return chain;
+ }
+
+ public AnnotationVisitor visitArray(final String name) {
+ ChainedAnnotationVisitor chain = null;
+ for (AnnotationVisitor visitor : m_visitors) {
+ AnnotationVisitor child = visitor.visitArray(name);
+ if (child != null) {
+ if (chain == null) {
+ chain = new ChainedAnnotationVisitor();
+ }
+ chain.getVisitors().add(child);
+ }
+
+ }
+ return chain;
+ }
+
+ public void visitEnd() {
+ for (AnnotationVisitor visitor : m_visitors) {
+ visitor.visitEnd();
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Classpath.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Classpath.java
new file mode 100644
index 0000000..ac5c3f1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Classpath.java
@@ -0,0 +1,180 @@
+/*
+ * 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.manipulator.util;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * An ordered list of classpath elements with set behaviour. A Classpath is immutable and thread safe.
+ * This class let retrieve an isolated classloader to load classes from a set of jars.
+ */
+public class Classpath implements Iterable<String> {
+
+ private final List<String> unmodifiableElements;
+
+ public static Classpath join(Classpath firstClasspath, Classpath secondClasspath) {
+ LinkedHashSet<String> accumulated = new LinkedHashSet<String>();
+ if (firstClasspath != null) firstClasspath.addTo(accumulated);
+ if (secondClasspath != null) secondClasspath.addTo(accumulated);
+ return new Classpath(accumulated);
+ }
+
+
+ private void addTo(Collection<String> c) {
+ c.addAll(unmodifiableElements);
+ }
+
+ private Classpath() {
+ this.unmodifiableElements = Collections.emptyList();
+ }
+
+
+ public Classpath(Classpath other, String additionalElement) {
+ ArrayList<String> elems = new ArrayList<String>(other.unmodifiableElements);
+ elems.add(additionalElement);
+ this.unmodifiableElements = Collections.unmodifiableList(elems);
+ }
+
+ public Classpath(Iterable<String> paths) {
+ List<String> newCp = new ArrayList<String>();
+ for (String element : paths) {
+ newCp.add(element);
+ }
+ this.unmodifiableElements = Collections.unmodifiableList(newCp);
+ }
+
+ public static Classpath emptyClasspath() {
+ return new Classpath();
+ }
+
+ public Classpath addClassPathElementUrl(String path) {
+ if (path == null) {
+ throw new IllegalArgumentException("Null is not a valid class path element url.");
+ }
+ return !unmodifiableElements.contains(path) ? new Classpath(this, path) : this;
+ }
+
+ public List<String> getClassPath() {
+ return unmodifiableElements;
+ }
+
+ public List<URL> getAsUrlList()
+ throws MalformedURLException {
+ List<URL> urls = new ArrayList<URL>();
+ for (String path : unmodifiableElements) {
+ File f = new File(path);
+ urls.add(f.toURI().toURL());
+ }
+ return urls;
+ }
+
+ public void writeToSystemProperty(String propertyName) {
+ StringBuilder sb = new StringBuilder();
+ for (String element : unmodifiableElements) {
+ sb.append(element).append(File.pathSeparatorChar);
+ }
+ System.setProperty(propertyName, sb.toString());
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Classpath classpath = (Classpath) o;
+
+ return !(unmodifiableElements
+ != null ? !unmodifiableElements.equals(classpath.unmodifiableElements) : classpath.unmodifiableElements != null);
+
+ }
+
+ public ClassLoader createClassLoader(ClassLoader parent, boolean childDelegation)
+ throws RuntimeException {
+ try {
+ List urls = getAsUrlList();
+ IsolatedClassLoader classLoader = new IsolatedClassLoader(parent, childDelegation);
+ for (Object url1 : urls) {
+ URL url = (URL) url1;
+ classLoader.addURL(url);
+ }
+ return classLoader;
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("When creating classloader", e);
+ }
+ }
+
+ public ClassLoader createClassLoader()
+ throws RuntimeException {
+ try {
+ List urls = getAsUrlList();
+ IsolatedClassLoader classLoader = new IsolatedClassLoader();
+ for (Object url1 : urls) {
+ URL url = (URL) url1;
+ classLoader.addURL(url);
+ }
+ return classLoader;
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("When creating classloader", e);
+ }
+ }
+
+
+ public int hashCode() {
+ return unmodifiableElements != null ? unmodifiableElements.hashCode() : 0;
+ }
+
+ public String getLogMessage(String descriptor) {
+ StringBuilder result = new StringBuilder();
+ result.append(descriptor).append(" classpath:");
+ for (String element : unmodifiableElements) {
+ result.append(" ").append(element);
+ }
+ return result.toString();
+ }
+
+ public String getCompactLogMessage(String descriptor) {
+ StringBuilder result = new StringBuilder();
+ result.append(descriptor).append(" classpath:");
+ for (String element : unmodifiableElements) {
+ result.append(" ");
+ if (element != null) {
+ int pos = element.lastIndexOf(File.separatorChar);
+ if (pos >= 0) {
+ result.append(element.substring(pos + 1));
+ } else {
+ result.append(element);
+ }
+
+ } else {
+ result.append(element);
+ }
+ }
+ return result.toString();
+ }
+
+ public Iterator<String> iterator() {
+ return unmodifiableElements.iterator();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
new file mode 100644
index 0000000..84f5084
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
@@ -0,0 +1,85 @@
+/*
+ * 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.manipulator.util;
+
+import java.lang.reflect.Array;
+
+/**
+ * {@code Collections5} is a static collection of methods being part of the Java6 Collections class.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Collections5 {
+
+ /**
+ * Copies the specified array, truncating or padding with nulls (if necessary)
+ * so the copy has the specified length. For all indices that are
+ * valid in both the original array and the copy, the two arrays will
+ * contain identical values. For any indices that are valid in the
+ * copy but not the original, the copy will contain <tt>null</tt>.
+ * Such indices will exist if and only if the specified length
+ * is greater than that of the original array.
+ * The resulting array is of exactly the same class as the original array.
+ *
+ * @param original the array to be copied
+ * @param newLength the length of the copy to be returned
+ * @return a copy of the original array, truncated or padded with nulls
+ * to obtain the specified length
+ * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+ * @throws NullPointerException if <tt>original</tt> is null
+ * @since 1.6
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T[] copyOf(T[] original, int newLength) {
+ return (T[]) copyOf(original, newLength, original.getClass());
+ }
+
+ /**
+ * Copies the specified array, truncating or padding with nulls (if necessary)
+ * so the copy has the specified length. For all indices that are
+ * valid in both the original array and the copy, the two arrays will
+ * contain identical values. For any indices that are valid in the
+ * copy but not the original, the copy will contain <tt>null</tt>.
+ * Such indices will exist if and only if the specified length
+ * is greater than that of the original array.
+ * The resulting array is of the class <tt>newType</tt>.
+ *
+ * @param original the array to be copied
+ * @param newLength the length of the copy to be returned
+ * @param newType the class of the copy to be returned
+ * @return a copy of the original array, truncated or padded with nulls
+ * to obtain the specified length
+ * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+ * @throws NullPointerException if <tt>original</tt> is null
+ * @throws ArrayStoreException if an element copied from
+ * <tt>original</tt> is not of a runtime type that can be stored in
+ * an array of class <tt>newType</tt>
+ * @since 1.6
+ */
+ public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
+ @SuppressWarnings("unchecked")
+ T[] copy = ((Object) newType == (Object) Object[].class)
+ ? (T[]) new Object[newLength]
+ : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+ System.arraycopy(original, 0, copy, 0,
+ Math.min(original.length, newLength));
+ return copy;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Constants.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Constants.java
new file mode 100644
index 0000000..5f897b3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Constants.java
@@ -0,0 +1,60 @@
+/*
+ * 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.manipulator.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * A static class to access the constant written during packaging.
+ */
+public class Constants {
+
+ public static String CONSTANTS_PATH = "META-INF/constants.properties";
+ public static String MANIPULATOR_VERSION = "manipulator.version";
+ public static String IPOJO_IMPORT_PACKAGES = "ipojo.import.packages";
+
+ private static Properties m_properties;
+
+ static {
+ load();
+ }
+
+ private static void load() {
+ m_properties = new Properties();
+ InputStream is = Constants.class.getClassLoader().getResourceAsStream(CONSTANTS_PATH);
+ try {
+ m_properties.load(is);
+ is.close();
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot load the 'constants' file");
+ }
+ }
+
+
+ public static String getVersion() {
+ return m_properties.getProperty(MANIPULATOR_VERSION);
+ }
+
+ public static String getPackageImportClause() {
+ return m_properties.getProperty(IPOJO_IMPORT_PACKAGES);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/IsolatedClassLoader.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/IsolatedClassLoader.java
new file mode 100644
index 0000000..f5a35f1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/IsolatedClassLoader.java
@@ -0,0 +1,85 @@
+/*
+ * 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.manipulator.util;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A classloader used by the {@link org.apache.felix.ipojo.manipulator.util.Classpath}.
+ */
+public class IsolatedClassLoader
+ extends URLClassLoader {
+ private final ClassLoader parent = ClassLoader.getSystemClassLoader();
+
+ private final Set<URL> urls = new HashSet<URL>();
+
+ private boolean childDelegation = true;
+
+ private static final URL[] EMPTY_URL_ARRAY = new URL[0];
+
+ public IsolatedClassLoader(ClassLoader parent, boolean childDelegation) {
+ super(EMPTY_URL_ARRAY, parent);
+ this.childDelegation = childDelegation;
+ }
+
+ public IsolatedClassLoader() {
+ super(EMPTY_URL_ARRAY, ClassLoader.getSystemClassLoader());
+ this.childDelegation = true;
+ }
+
+ public void addURL(URL url) {
+ // avoid duplicates
+ if (!urls.contains(url)) {
+ super.addURL(url);
+ urls.add(url);
+ }
+ }
+
+ public synchronized Class loadClass(String name)
+ throws ClassNotFoundException {
+ Class c;
+ if (childDelegation) {
+ c = findLoadedClass(name);
+
+ ClassNotFoundException ex = null;
+
+ if (c == null) {
+ try {
+ c = findClass(name);
+ } catch (ClassNotFoundException e) {
+ ex = e;
+ if (parent != null) {
+ c = parent.loadClass(name);
+ }
+ }
+ }
+
+ if (c == null) {
+ throw ex;
+ }
+ } else {
+ c = super.loadClass(name);
+ }
+
+ return c;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
new file mode 100644
index 0000000..5adfb72
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
@@ -0,0 +1,120 @@
+/*
+ * 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.manipulator.util;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * {@code Streams} is a utility class that helps to manipulate streams.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Metadatas {
+
+ /**
+ * Utility class: no public constructor
+ */
+ private Metadatas() {}
+
+ /**
+ * Return the {@literal classname} attribute value.
+ * @param meta metadata to be explored
+ * @return the {@literal classname} attribute value or {@literal null} if
+ * the attribute does not exists.
+ */
+ public static String getComponentType(Element meta) {
+ return meta.getAttribute("classname");
+ }
+
+ /**
+ * Looks for 'field' attribute in the given metadata.
+ * @param fields discovered fields (accumulator)
+ * @param metadata metadata to inspect
+ */
+ public static void findFields(List<String> fields, Element metadata) {
+ String field = metadata.getAttribute("field");
+ if (field != null && !fields.contains(field)) {
+ fields.add(field);
+ }
+ for (Element element : metadata.getElements()) {
+ findFields(fields, element);
+ }
+ }
+
+ /**
+ * Get packages referenced by component.
+ * @param metadata Element base for the search
+ * @return the Set of referenced packages.
+ */
+ public static Set<String> findReferredPackages(Element metadata) {
+
+ Set<String> packages = new HashSet<String>();
+ Set<String> specifications = findAttributes(metadata, "specification");
+
+ // Extract the package name from each specification (aka interface)
+ for (String specification : specifications) {
+ String name = getPackageName(specification);
+ if (name != null) {
+ packages.add(name);
+ }
+ }
+
+ return packages;
+ }
+
+ private static String getPackageName(String specification) {
+ int last = specification.lastIndexOf('.');
+ if (last != -1) {
+ return specification.substring(0, last);
+ }
+ return null;
+ }
+
+ /**
+ * Find all the values of the specified attribute in the given element.
+ * @param metadata Element to be traversed
+ * @param attributeName Search attribute name
+ * @return Set of attribute values (no duplicate).
+ */
+ public static Set<String> findAttributes(Element metadata, String attributeName) {
+ Set<String> referred = new HashSet<String>();
+
+ // Search in the given element
+ if (metadata.containsAttribute(attributeName)) {
+ referred.add(metadata.getAttribute(attributeName));
+ }
+
+ // Search in children
+ for (Element elem : metadata.getElements()) {
+ Set<String> found = findAttributes(elem, attributeName);
+ referred.addAll(found);
+ }
+
+ // Return all found values
+ return referred;
+ }
+
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java
new file mode 100644
index 0000000..6c5ea4f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulator.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@code Streams} is a utility class that helps to manipulate streams.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Streams {
+
+ private static final int ONE_HUNDRED_KB = 102400;
+
+ private static final int FOUR_KB = 4096;
+
+ /**
+ * Utility class: no public constructor
+ */
+ private Streams() {}
+
+ /**
+ * Close all the streams
+ * @param streams Streams to be closed
+ */
+ public static void close(Closeable... streams) {
+ for (Closeable stream : streams) {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // Ignored
+ }
+ }
+ }
+ }
+
+ /**
+ * Transfer the given {@link InputStream} content in the given {@link OutputStream}.
+ * @param is input
+ * @param os output
+ * @throws IOException if there is a transfer error.
+ */
+ public static void transfer(InputStream is, OutputStream os) throws IOException {
+ int read;
+ byte[] buffer = new byte[FOUR_KB];
+ while ((read = is.read(buffer)) != -1) {
+ os.write(buffer, 0, read);
+ }
+ }
+
+ /**
+ * Read the content of the given InputStream as a byte array.
+ * Notice that this method automatically closes the InputStream
+ * @param is source
+ * @return the content of the InputStream
+ * @throws IOException if stream's content cannot be read/written
+ */
+ public static byte[] readBytes(final InputStream is) throws IOException {
+ try {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ int read;
+ byte[] data = new byte[ONE_HUNDRED_KB];
+
+ while ((read = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, read);
+ }
+
+ buffer.flush();
+
+ return buffer.toByteArray();
+ } finally {
+ close(is);
+ }
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java
new file mode 100644
index 0000000..5ae8515
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java
@@ -0,0 +1,55 @@
+/*
+ * 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.manipulator.util;
+
+
+/**
+ * {@code Strings} is a utility class that helps to manipulate String.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Strings {
+
+ /**
+ * Utility class: no public constructor
+ */
+ private Strings() {}
+
+ /**
+ * Transform a FQN of a class (format {@literal org.objectweb.asm.Visitor}) into
+ * a normalized resource name ({@literal org/objectweb/asm/Visitor.class}).
+ * @param classname FQN of a class to be transformed
+ * @return resource name
+ */
+ public static String asResourcePath(String classname) {
+ return classname.replace('.', '/').concat(".class");
+ }
+
+ /**
+ * Transform a normalized resource path ({@literal org/objectweb/asm/Visitor.class}) into
+ * a fully qualified class name (format {@literal org.objectweb.asm.Visitor}).
+ * @param path normalized resource path to be transformed
+ * @return class name
+ */
+ public static String asClassName(String path) {
+ String transformed = path.replace('/', '.');
+ return transformed.substring(0, transformed.length() - ".class".length());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java
new file mode 100644
index 0000000..24700e9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.manipulator.visitor;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Empty ManipulationVisitor visitor.
+ * It is useful to extends this class to keep a working visitor chain.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationAdapter implements ManipulationVisitor {
+
+ private ManipulationVisitor m_delegate;
+
+ public ManipulationAdapter(ManipulationVisitor delegate) {
+ m_delegate = delegate;
+ }
+
+ public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+ return new ManipulationResultAdapter(m_delegate.visitManipulationResult(metadata));
+ }
+
+ public void visitMetadata(Element metadata) {
+ m_delegate.visitMetadata(metadata);
+ }
+
+ public void visitEnd() {
+ m_delegate.visitEnd();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java
new file mode 100644
index 0000000..d1d120e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.manipulator.visitor;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Empty ManipulationResultVisitor visitor.
+ * It is useful to extends this class to keep a working visitor chain.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationResultAdapter implements ManipulationResultVisitor {
+
+ private ManipulationResultVisitor m_delegate;
+
+ public ManipulationResultAdapter(ManipulationResultVisitor delegate) {
+ m_delegate = delegate;
+ }
+
+ public void visitClassStructure(Element structure) {
+ m_delegate.visitClassStructure(structure);
+ }
+
+ public void visitManipulatedResource(String type, byte[] resource) {
+ m_delegate.visitManipulatedResource(type, resource);
+ }
+
+ public void visitEnd() {
+ m_delegate.visitEnd();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java
new file mode 100644
index 0000000..44002f8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java
@@ -0,0 +1,104 @@
+/*
+ * 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.manipulator.visitor.check;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.visitor.ManipulationResultAdapter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This visitor checks that field referenced in the metadata are present in the bytecode.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CheckFieldConsistencyResultVisitor extends ManipulationResultAdapter {
+
+ /**
+ * Component's metadata.
+ */
+ private Element m_metadata;
+
+ /**
+ * Reporter for errors.
+ */
+ private Reporter m_reporter;
+
+ public CheckFieldConsistencyResultVisitor(ManipulationResultVisitor visitor) {
+ super(visitor);
+ }
+
+ public void setMetadata(Element metadata) {
+ this.m_metadata = metadata;
+ }
+
+ public void setReporter(Reporter reporter) {
+ this.m_reporter = reporter;
+ }
+
+ public void visitClassStructure(Element structure) {
+
+ List<String> fieldsInStructure = new ArrayList<String>();
+ collectStructuralFields(fieldsInStructure, structure);
+
+ List<String> fieldsInMetadata = new ArrayList<String>();
+ Metadatas.findFields(fieldsInMetadata, m_metadata);
+
+ checkReferredFieldsAreInStructure(fieldsInMetadata, fieldsInStructure);
+
+ // Do this at the end because the writer insert the manipulation
+ // metadata inside the component Element
+ // So to avoid duplicate find, we need to execute this code at the end
+ super.visitClassStructure(structure);
+
+ }
+
+ private void collectStructuralFields(List<String> fieldsInStructure, Element structure) {
+ Element[] fields = structure.getElements("field");
+ if (fields != null) {
+ for (Element field : fields) {
+ fieldsInStructure.add(field.getAttribute("name"));
+ }
+ }
+ }
+
+ /**
+ * Detects missing fields.
+ * If a referenced field does not exist in the class
+ * the method throws an error breaking the build process.
+ * @param fieldsInMetadata
+ * @param fieldsInStructure
+ */
+ private void checkReferredFieldsAreInStructure(List<String> fieldsInMetadata, List<String> fieldsInStructure) {
+ // Then, try to find each referred field in the given field map
+ for (String fieldName : fieldsInMetadata) {
+ if (!fieldsInStructure.contains(fieldName)) {
+ m_reporter.error("The field " + fieldName + " is referenced in the "
+ + "metadata but does not exist in the " + Metadatas.getComponentType(m_metadata)
+ + " class");
+ }
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java
new file mode 100644
index 0000000..22fe448
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.manipulator.visitor.check;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.visitor.ManipulationAdapter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Execute field verification.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CheckFieldConsistencyVisitor extends ManipulationAdapter {
+
+ private Reporter m_reporter;
+
+ public CheckFieldConsistencyVisitor(ManipulationVisitor visitor) {
+ super(visitor);
+ }
+
+ public void setReporter(Reporter reporter) {
+ this.m_reporter = reporter;
+ }
+
+ public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+ CheckFieldConsistencyResultVisitor rv = new CheckFieldConsistencyResultVisitor(super.visitManipulationResult(metadata));
+ rv.setMetadata(metadata);
+ rv.setReporter(m_reporter);
+ return rv;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java
new file mode 100644
index 0000000..d962d91
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.manipulator.visitor.writer;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Write manipulation result in the backend (store).
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulatedResourcesWriter implements ManipulationVisitor {
+
+ private ResourceStore m_resourceStore;
+ private Reporter m_reporter;
+ private List<ManipulatedResultWriter> m_writers;
+
+ public ManipulatedResourcesWriter() {
+ m_writers = new ArrayList<ManipulatedResultWriter>();
+ }
+
+ public void setResourceStore(ResourceStore resourceStore) {
+ m_resourceStore = resourceStore;
+ }
+
+ public void setReporter(Reporter reporter) {
+ m_reporter = reporter;
+ }
+
+ public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+ m_resourceStore.writeMetadata(metadata);
+ ManipulatedResultWriter writer = new ManipulatedResultWriter(metadata);
+ m_writers.add(writer);
+ return writer;
+ }
+
+ public void visitMetadata(Element metadata) {
+ m_resourceStore.writeMetadata(metadata);
+ }
+
+ public void visitEnd() {
+
+ try {
+ m_resourceStore.open();
+ for (ManipulatedResultWriter writer : m_writers) {
+ for (Map.Entry<String, byte[]> entry : writer.getResources().entrySet()) {
+ m_resourceStore.write(entry.getKey(), entry.getValue());
+ }
+ }
+ m_resourceStore.close();
+ } catch (IOException e) {
+ m_reporter.error("Cannot store manipulation result: " + e.getMessage());
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java
new file mode 100644
index 0000000..ad54083
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.manipulator.visitor.writer;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Gather manipulated bytecode.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulatedResultWriter implements ManipulationResultVisitor {
+
+ private Map<String, byte[]> m_resources;
+
+ private Element m_component;
+
+ public ManipulatedResultWriter(Element component) {
+ m_component = component;
+ m_resources = new HashMap<String, byte[]>();
+ }
+
+ public void visitClassStructure(Element structure) {
+ // Insert the manipulation structure in the component's metadata
+ m_component.addElement(structure);
+ }
+
+ public void visitManipulatedResource(String type, byte[] resource) {
+ m_resources.put(type, resource);
+ }
+
+ public void visitEnd() {
+ // nothing to do
+ }
+
+ public Map<String, byte[]> getResources() {
+ return m_resources;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
new file mode 100644
index 0000000..b194882
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.xml.parser;
+
+/**
+ * Exceptions thrown by parsers.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParseException extends Exception {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Parsing error.
+ * @param msg : the error message.
+ */
+ public ParseException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.java
new file mode 100644
index 0000000..d89e8c7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.java
@@ -0,0 +1,81 @@
+/*
+ * 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.xml.parser;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Entity Resolver loading embedded XML Schemas.
+ * This resolver avoid using a network connection to get schemas as they
+ * are loaded from the manipulator jar file.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SchemaResolver implements EntityResolver {
+
+ /**
+ * Directory where embedded schemas are copied.
+ */
+ public static final String XSD_PATH = "xsd";
+
+ /**
+ * Resolves systemIds to use embedded schemas. The schemas are loaded from
+ * the {@link SchemaResolver#XSD_PATH} directory with the current classloader.
+ * @param publicId the publicId
+ * @param systemId the systemId (Schema URL)
+ * @return the InputSource to load the schemas or <code>null</code> if the schema
+ * cannot be loaded (not embedded)
+ * @throws SAXException cannot happen
+ * @throws IOException when the embedded resource cannot be read correctly
+ * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
+ */
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException, IOException {
+
+ URL url = getURL(systemId);
+ if (url == null) {
+ // Cannot found the resource
+ return null;
+ } else {
+ return new InputSource(url.openStream());
+ }
+
+ }
+
+ /**
+ * Computes the local URL of the given system Id.
+ * This URL is computed by trying to load the resource from
+ * the current classloader. First, the last fragment (file name) of the system id
+ * url is extracted and the file is loaded from the {@link SchemaResolver#XSD_PATH}
+ * directory ('xsd/extracted')
+ * @param id the systemId to load
+ * @return the URL to the resources or <code>null</code> if the resource cannot be found.
+ */
+ private URL getURL(String id) {
+ int index = id.lastIndexOf('/');
+ String fragment = id.substring(index);
+ return this.getClass().getClassLoader().getResource(XSD_PATH + fragment);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
new file mode 100644
index 0000000..597b094
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -0,0 +1,295 @@
+/*
+ * 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.xml.parser;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * XML Metadata parser.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class XMLMetadataParser implements ContentHandler, ErrorHandler {
+
+ /**
+ * Element of the metadata.
+ */
+ private Element[] m_elements = new Element[0];
+
+ /**
+ * Get parsed metadata.
+ * The document must be parsed before calling this method.
+ * @return : all the metadata.
+ * @throws ParseException : occurs if an error occurs during the parsing.
+ */
+ public Element[] getMetadata() throws ParseException {
+ return m_elements[0].getElements();
+ }
+
+
+ /**
+ * Characters.
+ * @param ch : character
+ * @param start : start
+ * @param length : length
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+ */
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ // NOTHING TO DO
+
+ }
+
+
+ /**
+ * End the document.
+ * @throws SAXException : can never occrus.
+ * @see org.xml.sax.ContentHandler#endDocument()
+ */
+ public void endDocument() throws SAXException {
+ }
+
+
+ /**
+ * End of an element.
+ * @param namespaceURI : element namespace
+ * @param localName : local name
+ * @param qName : qualified name
+ * @throws SAXException : occurs when the element is malformed
+ * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+ // Get the last element of the list
+ Element lastElement = removeLastElement();
+
+ // The name is consistent
+ // Add this element last element with if it is not the root
+ if (m_elements.length != 0) {
+ Element newQueue = m_elements[m_elements.length - 1];
+ newQueue.addElement(lastElement);
+ } else {
+ // It is the last element
+ addElement(lastElement);
+ }
+
+ }
+
+ /**
+ * End prefix mapping.
+ * @param prefix : ended prefix
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
+ */
+ public void endPrefixMapping(String prefix) throws SAXException {
+ // NOTHING TO DO
+ }
+
+
+ /**
+ * Ignore whitespace.
+ * @param ch : character
+ * @param start : start
+ * @param length : length
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
+ */
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ // NOTHING TO DO
+ }
+
+ /**
+ * Process an instruction.
+ * @param target : target
+ * @param data : data
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
+ */
+ public void processingInstruction(String target, String data) throws SAXException {
+ // DO NOTHING
+ }
+
+ /**
+ * Set Document locator.
+ * @param locator : new locator.
+ * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
+ */
+ public void setDocumentLocator(Locator locator) {
+ // NOTHING TO DO
+
+ }
+
+ /**
+ * Skipped entity.
+ * @param name : name.
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
+ */
+ public void skippedEntity(String name) throws SAXException {
+ // NOTHING TO DO
+
+ }
+
+ /**
+ * Start a document.
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#startDocument()
+ */
+ public void startDocument() throws SAXException {
+ }
+
+
+ /**
+ * Start an element.
+ * @param namespaceURI : element namespace.
+ * @param localName : local element.
+ * @param qName : qualified name.
+ * @param atts : attribute
+ * @throws SAXException : occurs if the element cannot be parsed correctly.
+ * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+ */
+ public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+ String namespace = namespaceURI;
+ if (namespaceURI != null
+ && (namespaceURI.equalsIgnoreCase("org.apache.felix.ipojo") || namespaceURI.equalsIgnoreCase("org.apache.felix.ipojo.composite"))) {
+ namespace = null; // Remove the 'org.apache.felix.ipojo' namespace
+ }
+
+ Element elem = new Element(localName, namespace);
+ for (int i = 0; i < atts.getLength(); i++) {
+ String name = (String) atts.getLocalName(i);
+ String ns = (String) atts.getURI(i);
+ String value = (String) atts.getValue(i);
+ Attribute att = new Attribute(name, ns, value);
+ elem.addAttribute(att);
+ }
+
+ addElement(elem);
+
+ }
+
+ /**
+ * Start a prefix mapping.
+ * @param prefix : prefix.
+ * @param uri : uri.
+ * @throws SAXException : can never occurs.
+ * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
+ */
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ // NOTHING TO DO
+
+ }
+
+ /**
+ * Add an element.
+ * @param elem : the element to add
+ */
+ private void addElement(Element elem) {
+ for (int i = 0; (m_elements != null) && (i < m_elements.length); i++) {
+ if (m_elements[i] == elem) {
+ return;
+ }
+ }
+
+ if (m_elements != null) {
+ Element[] newElementsList = new Element[m_elements.length + 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, m_elements.length);
+ newElementsList[m_elements.length] = elem;
+ m_elements = newElementsList;
+ } else {
+ m_elements = new Element[] { elem };
+ }
+ }
+
+ /**
+ * Remove an element.
+ * @return : the removed element.
+ */
+ private Element removeLastElement() {
+ int idx;
+ idx = m_elements.length - 1;
+ Element last = m_elements[idx];
+ if (idx >= 0) {
+ if ((m_elements.length - 1) == 0) {
+ // It is the last element of the list;
+ m_elements = new Element[0];
+ } else {
+ // Remove the last element of the list :
+ Element[] newElementsList = new Element[m_elements.length - 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, idx);
+ m_elements = newElementsList;
+ }
+ }
+ return last;
+ }
+
+
+ /**
+ * An error occurs during the XML-Schema checking.
+ * This method propagates the error except if the error concerns
+ * no XML-Schemas are used (<code>cvc-elt.1</code>).
+ * @param saxparseexception the checking error
+ * @throws SAXException the propagated exception
+ * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
+ */
+ public void error(SAXParseException saxparseexception) throws SAXException {
+ if (saxparseexception.getMessage().contains("cvc-elt.1")) {
+ return; // Do not throw an exception when no schema defined.
+ }
+ throw saxparseexception;
+ }
+
+
+ /**
+ * A fatal error occurs during the XML-Schema checking.
+ * This method always propagates the error.
+ * @param saxparseexception the checking error
+ * @throws SAXException the propagated exception
+ * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
+ */
+ public void fatalError(SAXParseException saxparseexception)
+ throws SAXException {
+ //TODO use reporter
+
+ System.err.println("Fatal error during XML-Schema parsing : " + saxparseexception);
+ throw saxparseexception;
+ }
+
+ /**
+ * A warning was detected during the XML-Schema checking.
+ * This method always propagate the warning message to
+ * {@link System#out}.
+ * @param saxparseexception the checking error
+ * @throws SAXException nothing.
+ * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
+ */
+ public void warning(SAXParseException saxparseexception)
+ throws SAXException {
+ // TODO use reporter
+ System.err.println("Warning : an error was detected in the metadata file : " + saxparseexception);
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/resources/META-INF/constants.properties b/ipojo/manipulator/manipulator/src/main/resources/META-INF/constants.properties
new file mode 100644
index 0000000..d070319
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/META-INF/constants.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# This file define the different constant we use in the manipulator. This file is filtered by Maven.
+manipulator.version=${project.version}
+ipojo.import.packages=${ipojo.import.packages}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module b/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
new file mode 100644
index 0000000..d3b15f9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
@@ -0,0 +1 @@
+org.apache.felix.ipojo.manipulator.metadata.annotation.module.DefaultBindingModule
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/composite.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/composite.xsd
new file mode 100644
index 0000000..f127ddd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/composite.xsd
@@ -0,0 +1,147 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema elementFormDefault="qualified"
+ targetNamespace="org.apache.felix.ipojo.composite"
+ xmlns="org.apache.felix.ipojo.composite"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ipojo="org.apache.felix.ipojo">
+
+ <xs:import namespace="org.apache.felix.ipojo" schemaLocation="http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"></xs:import>
+ <xs:complexType name="CompositeType">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="subservice" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded">
+ </xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional"></xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean"
+ use="optional">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="subservice" type="SubserviceType" />
+ <xs:element name="provides" type="CompositeProvidesType" />
+
+ <xs:complexType name="CompositeProvidesType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+ <xs:sequence>
+ <xs:element name="delegation" type="DelegationType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+
+ <xs:attribute name="action">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="implement"></xs:enumeration>
+ <xs:enumeration value="export"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="SubserviceType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="action" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="import"></xs:enumeration>
+ <xs:enumeration value="instantiate"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+ <xs:attribute name="context-source" type="xs:string"
+ use="optional">
+ </xs:attribute>
+ <xs:attribute name="scope">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"></xs:enumeration>
+ <xs:enumeration value="composite"></xs:enumeration>
+ <xs:enumeration value="composite+global"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:simpleType name="actionType">
+ <xs:restriction base="xs:string"></xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="CompositePropertyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType" minOccurs="0" maxOccurs="unbounded"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional"></xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="CompositeInstanceType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="component" type="xs:string"
+ use="required">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="instance" type="CompositeInstanceType"></xs:element>
+
+ <xs:element name="composite" type="CompositeType"></xs:element>
+
+ <xs:complexType name="DelegationType">
+ <xs:attribute name="method" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="policy" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="all"></xs:enumeration>
+ <xs:enumeration value="one"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
new file mode 100644
index 0000000..3c729c9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
@@ -0,0 +1,704 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema elementFormDefault="qualified" targetNamespace="org.apache.felix.ipojo"
+ xmlns="org.apache.felix.ipojo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:annotation>
+ <xs:documentation>iPOJO Core XML-Schema. This grammars models iPOJO descriptor using core
+ features. It provides several extensibility mechanism in order to compose this schema with
+ external handlers and other component implementation type such as
+ compositions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:element name="ipojo">
+ <xs:complexType>
+ <xs:annotation>
+ <xs:documentation>iPOJO top level element.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="handler" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The handler declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The instance declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="component" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The component type declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="HandlerType">
+ <xs:annotation>
+ <xs:documentation>Description of the handler.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence maxOccurs="unbounded" minOccurs="0">
+ <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="skip"
+ ></xs:any>
+ </xs:sequence>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The implementation class of the handler. The specified class must
+ implement (direcly or not) the "org.apache.felix.ipojo.Handler"
+ interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="namespace" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The XML namespace of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional" fixed="false">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is not exposed. This allows handler introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="level" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>The start level of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstanceType">
+ <xs:annotation>
+ <xs:documentation>Describes an instance of a component.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>The instance props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="component" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>The name of the instance component type.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The (unique) name of the instance.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The version of the factory to use.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a property of an instance configuration.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="property" type="InstancePropertyType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property. Can be optional if a property is inside a structure.
+ The 'instance.name' property has a special semantic as it will be used as the instance
+ name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Value of the property. Can be null for property containing other
+ props.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property, used to create the adequate object. Supported values
+ are list, array, dictionary and map.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RootElementType"/>
+ <xs:complexType name="ComponentType">
+ <xs:annotation>
+ <xs:documentation>Declares an atomic (i.e. primitive) component type.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="callback" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the method(s) to invoke when the component's state
+ changes.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the component provided service(s). By default, all implemented
+ interfaces are published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the service requirements of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="properties" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the properties of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="controller" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>Lifecycle controller for this component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the name of the component type. This name is used to identify
+ the factory attached to this type. If not specified, the factory name is the
+ implementation class name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Determines if the component type is public or private. A public factory
+ (default) can be used from any bundles.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the implementation class of the component
+ type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is exposed. This allows instance introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immediate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Creates the object of the component implementation type as soon as the
+ component instance becomes valid. The default value is "true" if the component doesn't
+ provide any service, "false" otherwise.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory-method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Factory method called to create POJO objects instead of the constructor.
+ The specified method must be a static method of the implementation class returning an
+ instance of this implementation class. The factory method can receive the bundle context
+ in argument.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Set the version of this component type</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RequiresType">
+ <xs:annotation>
+ <xs:documentation>Description of component services requirements.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="ServiceDependencyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="callback" type="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Service requirement method invocation description. Here can be
+ specified a bind method called when a service appears and an unbind method called
+ when a service disappears.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>The interface describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type
+ of this field is a list, vector, collection and set. This attribute is deprecated, use
+ 'specification'.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The name of the field representing the service dependency in the
+ implementation class.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="nullable" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enable or disable the Nullable pattern on optional service
+ dependencies. By default, Nullable pattern is enabled. If disabled, iPOJO will inject
+ null instead of a Nullable object.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="default-implementation" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the default implementation class for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ default-implementation (nullary constructor) and injects it. The given class must
+ implement the required service interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </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 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="from" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specific service provider. The dependency can only be fulfilled by the
+ component with the matching name, or by the service with a matching
+ PID.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="proxy" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or Disable the proxy injection (on field
+ injection)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="scope" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"/>
+ <xs:enumeration value="composite"/>
+ <xs:enumeration value="composite+global"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Dependency callbacks are used to receive notification when service providers
+ arrive and leave.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Method to call</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" use="required">
+ <xs:annotation>
+ <xs:documentation>Type of callback (bind, unbind, or updated). Bind means that the method
+ will be called when a provider arrives. Unbind means that the method will be called when a
+ provider leaves. Updated means that a service was modified but is still valid for the
+ service dependency.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="bind"/>
+ <xs:enumeration value="unbind"/>
+ <xs:enumeration value="modified"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="CallbackType">
+ <xs:annotation>
+ <xs:documentation>Lifecycle Callback. Allows a POJO to be notified when the instance becomes
+ valid or invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the method to call on the transition.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="transition" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the transition when the callback needs to be
+ invoked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>Lifecycle transition state. "validate" means that the component's
+ instance was invalid and becomes valid, "invalidate" means that the component's intance
+ was valid and becomes invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="validate"/>
+ <xs:enumeration value="invalidate"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ContextType">
+ <xs:annotation>
+ <xs:documentation>Allows injecting the OSGi bundle context into the component.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the method receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the field receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="constructor-parameter" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the index of the parameter (0-based) receiving the bundle
+ context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="context" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the context source.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>iPOJO supports two bundle context 'sources': component and instance. Component
+ is the bundle context of the bundle declaring the component, while instance is the bundle
+ context of the bundle declaring the instance. Obviously, they are the same when the instance
+ is declared in the same bundle as the component. By default, it uses 'component'.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="instance"/>
+ <xs:enumeration value="component"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="provides" type="ProvidesType" id="provides"/>
+ <xs:complexType name="ProvidesType">
+ <xs:annotation>
+ <xs:documentation>Provided service(s) description.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>List of service specific props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="controller" minOccurs="0" maxOccurs="1" type="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Service Controller impacting the current provided
+ service
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Deprecated attribute, use 'specifications' instead of
+ 'interface'
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specifications" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The list of service specifications (i.e. interfaces) to expose. By
+ default, all interfaces implemented by the component implementation class are
+ published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="strategy" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>POJO creation strategy. By default, the POJO object is created once
+ (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi
+ service factory policy (one object object per asking bundle). INSTANCE allows creating one
+ different POJO object per asking instance. Finally, a custom strategy can be used by
+ specifying the qualified name of the class extending CreationPolicy
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-registration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service registration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-unregistration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service unregistration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Defines a service controller.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Field of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Intiail value of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="PropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a component property.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Field of the property</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Setter method of the property. This method is called to inject property
+ value.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Default value of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="mandatory" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as mandatory. A mandatory property MUST receive a value
+ either in the component type description or in the instance configuration. Properties are
+ optional by default.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immutable" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as immutable. An immutable property is inherited by the component
+ instance but the value cannot be overridden.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="callback" type="CallbackType" id="callback"/>
+ <xs:element name="context" type="ContextType" id="context"/>
+ <xs:element name="controller" type="ControllerType" id="controller">
+ <xs:annotation>
+ <xs:documentation/>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="requires" type="RequiresType" id="requires"/>
+ <xs:element name="component" type="ComponentType" id="component"/>
+ <xs:element name="handler" type="HandlerType" id="handler"/>
+ <xs:element name="instance" type="InstanceType" id="instance"/>
+
+ <xs:element name="properties" type="PropertiesType" id="properties"/>
+ <xs:complexType name="PropertiesType">
+ <xs:annotation>
+ <xs:documentation>List of component, instance or service props. This field will receive
+ the property value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>The list of props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="propagation" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Propagation of the component properties to the provided services. If this
+ parameter is set to "true", each time properties are reconfigured, they are propagated to
+ each service published by the component.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="pid" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Unique identifier used to reconfigure components properties (via Managed
+ Services) with the Configuration Admin.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="updated" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Method called when a reconfiguration is done</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ServiceDependencyType">
+ <xs:attribute name="specification" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The specification describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type of
+ this field is a list, vector, collection and set.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="optional" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency optionality</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="aggregate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency cardinality.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="policy" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the binding policy of the dependency. Three policies are supported.
+ The dynamic policy supports service providers dynamism. The static policy freezes the
+ provider set as soon as the dependency is used. The dynamic-priority policy is an
+ extension of the dynamic policy, but providers are ranked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="dynamic"/>
+ <xs:enumeration value="static"/>
+ <xs:enumeration value="dynamic-priority"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="comparator" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The comparator attribute allows specifying the class used to compare
+ providers. This class must implemented the java.util.Comparator class and must support the
+ comparison of service references.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="filter" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>LDAP filter used to filter providers</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>id of the service dependency. The id allows to identify and to refer to
+ this dependency.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ControllerType">
+ <xs:annotation>
+ <xs:documentation>Specifies the lifecycle controller of a component, which allows to validate
+ or invalidate component instances.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the component lifecycle controller field. The type of the
+ specified field must be boolean. Setting the value of the specified field to "true" means
+ the validation of the component instance while setting it to "false" means the
+ invalidation of the component instance.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/event-admin.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/event-admin.xsd
new file mode 100644
index 0000000..d3948e6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/event-admin.xsd
@@ -0,0 +1,90 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.event"
+ xmlns="org.apache.felix.ipojo.handlers.event"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+
+ <xs:complexType name="PublisherType">
+ <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: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>
+ <xs:element name="subscriber" type="SubscriberType"></xs:element>
+
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/extender-pattern.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/extender-pattern.xsd
new file mode 100644
index 0000000..dc39757
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/extender-pattern.xsd
@@ -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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.extender"
+ xmlns="org.apache.felix.ipojo.extender"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="extender" type="ExtenderType"></xs:element>
+ <xs:complexType name="ExtenderType">
+ <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
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/jmx.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/jmx.xsd
new file mode 100644
index 0000000..09b9509
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/jmx.xsd
@@ -0,0 +1,177 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.jmx"
+ xmlns="org.apache.felix.ipojo.handlers.jmx"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="config" type="JMXType"></xs:element>
+
+ <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: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="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: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: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:annotation>
+ <xs:documentation>Enable or disable attribute change notification sending for this property. If set to "true", 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: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
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/temporal.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/temporal.xsd
new file mode 100644
index 0000000..cecc68b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/temporal.xsd
@@ -0,0 +1,61 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handler.temporal"
+ xmlns="org.apache.felix.ipojo.handler.temporal"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="requires" type="TemporalServiceDependencyType"></xs:element>
+
+ <xs:complexType name="TemporalServiceDependencyType">
+
+ <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="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The dependency id</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: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:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" use="optional" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>Enables or Disables the proxy injection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specification" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Specifies the looked service specification. This attribute is mandatory when injecting in a Collection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd
new file mode 100644
index 0000000..0c8ebb2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd
@@ -0,0 +1,45 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema targetNamespace="org.apache.felix.ipojo.whiteboard"
+ xmlns="org.apache.felix.ipojo.whiteboard"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="wbp" type="WBPType"></xs:element>
+ <xs:complexType name="WBPType">
+ <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
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
new file mode 100644
index 0000000..953ff3a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+
+/**
+ * Component Instance Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface ComponentInstance {
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
new file mode 100644
index 0000000..440151e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import java.util.Set;
+
+/**
+ * Instance Manager Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public class InstanceManager {
+
+ public Set getRegistredFields() {
+ return null;
+ }
+
+ public Set getRegistredMethods() {
+ return null;
+ }
+
+ public void onEntry(Object pojo, String methodId, Object[] args) {
+
+ }
+
+ public void onExit(Object pojo, String methodId, Object[] args) {
+
+ }
+
+ public void onError(Object pojo, String methodId, Throwable error) {
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
new file mode 100644
index 0000000..0588500
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * POJO Interface fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface Pojo {
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
new file mode 100644
index 0000000..773a2a3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
@@ -0,0 +1,129 @@
+/*
+ * 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.manipulation;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.objectweb.asm.*;
+import org.osgi.framework.BundleContext;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ClassCheckerTestCase extends TestCase {
+
+ public void testIsAlreadyManipulatedWithNotManipulatedResource() throws Exception {
+ ClassChecker checker = check(resource("test/SimplePojo.class"));
+ assertFalse(checker.isAlreadyManipulated());
+ }
+
+ public void testIsAlreadyManipulatedWithManipulatedResource() throws Exception {
+ ClassChecker checker = check(manipulate(resource("test/SimplePojo.class")));
+ assertTrue(checker.isAlreadyManipulated());
+ }
+
+ public void testMetadataForAlreadyManipulatedClassAreCleaned() throws Exception {
+ ClassChecker checker = check(manipulate(resource("test/AnnotatedComponent.class")));
+
+ // Check implemented interfaces
+ List<String> interfaces = checker.getInterfaces();
+ assertTrue(interfaces.isEmpty());
+
+ // Check super class
+ assertNull(checker.getSuperClass());
+
+ // Check inner classes
+ Collection<String> inner = checker.getInnerClasses();
+ assertTrue(inner.isEmpty());
+
+ // Ensure fields are correctly filtered
+ Map<String, String> fields = checker.getFields();
+ assertEquals(1, fields.size());
+ assertEquals("java.lang.String", fields.get("prop"));
+
+ // Ensure methods are also correctly filtered
+ List<MethodDescriptor> descriptors = checker.getMethods();
+ assertEquals(2, descriptors.size());
+
+ // AnnotatedComponent(BundleContext)
+ MethodDescriptor constructor = searchMethod("$init", descriptors);
+ assertNotNull(constructor);
+ Type[] arguments = Type.getArgumentTypes(constructor.getDescriptor());
+ assertEquals(1, arguments.length);
+ assertEquals(Type.getType(BundleContext.class), arguments[0]);
+
+ // @FakeAnnotation
+ // AnnotatedComponent.annotatedMethod():Void
+ MethodDescriptor method = searchMethod("annotatedMethod", descriptors);
+ assertNotNull(method);
+ assertEquals("()V", method.getDescriptor()); // return void + no params
+ assertAnnotationIsAlone(method, "Ltest/FakeAnnotation;");
+
+
+ }
+
+ private void assertAnnotationIsAlone(MethodDescriptor method, String desc) {
+ List<ClassChecker.AnnotationDescriptor> annotations = method.getAnnotations();
+
+ assertEquals(1, annotations.size());
+ ClassChecker.AnnotationDescriptor annotationDescriptor = annotations.get(0);
+ MethodVisitor mv = mock(MethodVisitor.class);
+ when(mv.visitAnnotation(desc, true)).thenReturn(new AnnotationVisitor(Opcodes.ASM5) {});
+ annotationDescriptor.visitAnnotation(mv);
+ }
+
+ private MethodDescriptor searchMethod(String methodName, List<MethodDescriptor> descriptors) {
+ for (MethodDescriptor descriptor : descriptors) {
+ if (methodName.equals(descriptor.getName())) {
+ return descriptor;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] manipulate(byte[] input) throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ manipulator.prepare(input);
+ return manipulator.manipulate(input);
+ }
+
+ private byte[] resource(String name) throws Exception {
+ return ManipulatorTest.getBytesFromFile(new File("target/test-classes/" + name));
+ }
+
+ private ClassChecker check(byte[] resource) throws Exception {
+ ClassChecker checker = new ClassChecker();
+ ByteArrayInputStream is = new ByteArrayInputStream(resource);
+ try {
+ ClassReader classReader = new ClassReader(is);
+ classReader.accept(checker, ClassReader.SKIP_FRAMES);
+ } finally {
+ Streams.close(is);
+ }
+ return checker;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/DirManipulationTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/DirManipulationTest.java
new file mode 100644
index 0000000..15a5285
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/DirManipulationTest.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.junit.Test;
+
+import test.AnnotatedComponent;
+
+import junit.framework.TestCase;
+
+/**
+ * Test cases for Pojoization.directoryManipulation()
+ *
+ */
+public class DirManipulationTest extends TestCase {
+
+ /**
+ * Test case for FELIX-3466.
+ *
+ * Checks if directory manipulation, uses the supplied manifest file as
+ * output.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testManifestLocationKept() throws IOException {
+ Pojoization pojoizator = new Pojoization();
+ File tmpDir = null, manifestFile = null, testClass = null;
+
+ // To obtain OS's temp directory.
+ File tmpFile = File.createTempFile("pojodir", ".dir");
+ String tmpPath = tmpFile.getAbsolutePath();
+ tmpFile.delete();
+
+ // Creating directory on temp location
+ tmpDir = new File(tmpPath);
+ tmpDir.mkdir();
+ tmpDir.deleteOnExit();
+
+ // Create manifest file under temp directory
+ manifestFile = new File(tmpDir, "MANIFEST.MF");
+ new FileOutputStream(manifestFile).write("Manifest-Version: 1.0\r\n"
+ .getBytes());
+ manifestFile.deleteOnExit();
+
+ // Just to ensure it is not deleted later from test classes.
+ AnnotatedComponent safe;
+
+ // Annotated Class File
+ File annotedClassPackage = new File(tmpDir, "test");
+ annotedClassPackage.deleteOnExit();
+ annotedClassPackage.mkdir();
+ testClass = new File(annotedClassPackage, "AnnotatedComponent.class");
+ testClass.deleteOnExit();
+ FileOutputStream os = new FileOutputStream(testClass);
+ os.write(ManipulatorTest.getBytesFromFile(new File(
+ "target/test-classes/test/AnnotatedComponent.class")));
+ os.close();
+
+ // Issue directory manipulation
+ pojoizator.directoryPojoization(tmpDir, null, manifestFile, null);
+
+ // Check if supplied manifest file is altered in place
+ BufferedReader fi = new BufferedReader(new FileReader(manifestFile));
+ String manifestLine;
+ while ((manifestLine = fi.readLine()) != null) {
+ if (manifestLine.contains("iPOJO-Components")) {
+ assertTrue(true);
+ return;
+ }
+ }
+
+ assertTrue(
+ "Directory Manipulation didn't use supplied manifest file as output",
+ false);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java
new file mode 100644
index 0000000..4496609
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java
@@ -0,0 +1,399 @@
+/*
+ * 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.manipulation;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Pojo;
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+
+import static junit.framework.Assert.assertEquals;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks the inner class manipulation
+ */
+public class InnerClassAdapterTest {
+
+ public static String baseClassDirectory = "target/test-classes/";
+
+ public static ManipulatedClassLoader manipulate(String className, Manipulator manipulator) throws IOException {
+ final File mainClassFile = new File(baseClassDirectory + className.replace(".", "/") + ".class");
+ byte[] bytecode = ManipulatorTest.getBytesFromFile(
+ mainClassFile);
+
+ // Preparation.
+ try {
+ manipulator.prepare(bytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot read " + className);
+ }
+
+ // Inner class preparation
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = ManipulatorTest.getBytesFromFile(new File(baseClassDirectory + resourcePath));
+ manipulator.prepareInnerClass(inner, innerClassBytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot find or analyze inner class '" + resourcePath + "'");
+ }
+ }
+
+ // Now manipulate the classes.
+ byte[] out = new byte[0];
+ try {
+ out = manipulator.manipulate(bytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot manipulate the class " + className + " : " + e.getMessage());
+ }
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader(className, out);
+
+ // Visit inner classes
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = ManipulatorTest.getBytesFromFile(new File(baseClassDirectory + resourcePath));
+ byte[] manipulated = manipulator.manipulateInnerClass(inner, innerClassBytecode);
+ classloader.addInnerClass(inner.replace("/", "."), manipulated);
+ } catch (IOException e) {
+ Assert.fail("Cannot find inner class '" + resourcePath + "'");
+ }
+ }
+
+ // Lookup for all the other inner classes (not manipulated)
+ File[] files = mainClassFile.getParentFile().listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.startsWith(mainClassFile.getName().substring(0, mainClassFile.getName().length() -
+ ".class".length()) + "$");
+ }
+ });
+
+ for (File f : files) {
+ String name = className + f.getName().substring(f.getName().indexOf("$"));
+ name = name.substring(0, name.length() - ".class".length());
+ byte[] innerClassBytecode = ManipulatorTest.getBytesFromFile(f);
+ classloader.addInnerClassIfNotAlreadyDefined(name, innerClassBytecode);
+ }
+
+ return classloader;
+ }
+
+ public static ManipulatedClassLoader manipulate(String className, Manipulator manipulator,
+ ManipulatedClassLoader initial) throws IOException {
+ byte[] bytecode = initial.get(className);
+ final File mainClassFile = new File(baseClassDirectory + className.replace(".", "/") + ".class");
+ String mainClass = className;
+
+ // Preparation.
+ try {
+ manipulator.prepare(bytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot read " + className);
+ }
+
+ // Inner class preparation
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = initial.get(inner.replace("/", "."));
+ manipulator.prepareInnerClass(inner, innerClassBytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot find or analyze inner class '" + resourcePath + "'");
+ }
+ }
+
+ // Now manipulate the classes.
+ byte[] out = new byte[0];
+ try {
+ out = manipulator.manipulate(bytecode);
+ } catch (IOException e) {
+ Assert.fail("Cannot manipulate the class " + className + " : " + e.getMessage());
+ }
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader(className, out);
+
+ // Visit inner classes
+ for (String inner : manipulator.getInnerClasses()) {
+ // Get the bytecode and start manipulation
+ String resourcePath = inner + ".class";
+ byte[] innerClassBytecode;
+ try {
+ innerClassBytecode = initial.get(inner.replace("/", "."));
+ byte[] manipulated = manipulator.manipulateInnerClass(inner, innerClassBytecode);
+ classloader.addInnerClass(inner.replace("/", "."), manipulated);
+ } catch (IOException e) {
+ Assert.fail("Cannot find inner class '" + resourcePath + "'");
+ }
+ }
+
+ // Lookup for all the other inner classes (not manipulated)
+ File[] files = mainClassFile.getParentFile().listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.startsWith(mainClassFile.getName().substring(0, mainClassFile.getName().length() -
+ ".class".length()) + "$");
+ }
+ });
+
+
+ for (File f : files) {
+ String name = className + f.getName().substring(f.getName().indexOf("$"));
+ name = name.substring(0, name.length() - ".class".length());
+ byte[] innerClassBytecode = ManipulatorTest.getBytesFromFile(f);
+ classloader.addInnerClassIfNotAlreadyDefined(name, innerClassBytecode);
+ }
+
+ return classloader;
+ }
+
+ private static Element getInnerClassMetadataByName(Element[] inners, String name) {
+ for (Element element : inners) {
+ if (name.equals(element.getAttribute("name"))) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ private static Element getMethodByName(Element[] methods, String name) {
+ for (Element element : methods) {
+ if (name.equals(element.getAttribute("name"))) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testManipulatingTheInner() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.PojoWithInner";
+ byte[] origin = ManipulatorTest.getBytesFromFile(new File(baseClassDirectory + className.replace(".",
+ "/") + ".class"));
+
+ ManipulatedClassLoader classloader = manipulate(className, manipulator);
+
+ Class cl = classloader.findClass(className);
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+ Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+
+ System.out.println(manipulator.getManipulationMetadata());
+
+ // The manipulation add stuff to the class.
+ Assert.assertTrue(classloader.get(className).length > origin.length);
+
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (Constructor cst2 : csts) {
+ System.out.println(Arrays.asList(cst2.getParameterTypes()));
+ if (cst2.getParameterTypes().length == 1 &&
+ cst2.getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = cst2;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // We still have the empty constructor
+ found = false;
+ csts = cl.getDeclaredConstructors();
+ for (Constructor cst1 : csts) {
+ System.out.println(Arrays.asList(cst1.getParameterTypes()));
+ if (cst1.getParameterTypes().length == 0) {
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ InstanceManager im = Mockito.mock(InstanceManager.class);
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[]{im});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+ Method method = cl.getMethod("doSomething", new Class[0]);
+ Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+ }
+
+ @Test
+ public void testInnerClasses() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ ManipulatedClassLoader classloader = manipulate(className, manipulator);
+
+
+ Class clazz = classloader.findClass(className);
+ Assert.assertNotNull(clazz);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+ Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+ // We should have found only 2 inner classes.
+ assertThat(manipulator.getInnerClasses().size()).isEqualTo(3);
+
+ // Check that all inner classes are manipulated.
+ InstanceManager im = Mockito.mock(InstanceManager.class);
+ Constructor constructor = clazz.getDeclaredConstructor(InstanceManager.class);
+ constructor.setAccessible(true);
+ Object pojo = constructor.newInstance(im);
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+ Method method = clazz.getMethod("doSomething", new Class[0]);
+ String result = (String) method.invoke(pojo);
+ assertEquals(result, "foofoofoofoo");
+ }
+
+ @Test
+ public void testDoubleManipulation() throws IOException, ClassNotFoundException, NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException, InstantiationException {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ ManipulatedClassLoader classloader = manipulate(className, manipulator);
+
+ manipulator = new Manipulator(this.getClass().getClassLoader());
+ classloader = manipulate(className, manipulator, classloader);
+
+ Class clazz = classloader.findClass(className);
+ Assert.assertNotNull(clazz);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+ Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+ // We should have found only 2 inner classes.
+ assertThat(manipulator.getInnerClasses().size()).isEqualTo(3);
+
+ // Check that all inner classes are manipulated.
+ InstanceManager im = Mockito.mock(InstanceManager.class);
+ Constructor constructor = clazz.getDeclaredConstructor(InstanceManager.class);
+ constructor.setAccessible(true);
+ Object pojo = constructor.newInstance(im);
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+ Method method = clazz.getMethod("doSomething", new Class[0]);
+ String result = (String) method.invoke(pojo);
+ assertEquals(result, "foofoofoofoo");
+ }
+
+ @Test
+ public void testThatManipulationMetadataContainsTheInnerClasses() throws IOException, ClassNotFoundException,
+ NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ manipulate(className, manipulator);
+
+ assertThat(manipulator.getInnerClasses().size()).isEqualTo(3);
+
+ Element manipulation = manipulator.getManipulationMetadata();
+ System.out.println(manipulation);
+ Element[] inners = manipulation.getElements("inner");
+ assertThat(inners.length).isEqualTo(3);
+
+ Element inner = getInnerClassMetadataByName(inners, "MyInnerWithANativeMethod");
+ assertThat(inner).isNotNull();
+ assertThat(getMethodByName(inner.getElements("method"), "foo")).isNotNull();
+
+ inner = getInnerClassMetadataByName(inners, "MyInnerClass");
+ assertThat(inner).isNotNull();
+ assertThat(getMethodByName(inner.getElements("method"), "foo")).isNotNull();
+
+ inner = getInnerClassMetadataByName(inners, "1");
+ assertThat(inner).isNotNull();
+ assertThat(getMethodByName(inner.getElements("method"), "compute")).isNotNull();
+ }
+
+ @Test
+ public void testThatTheClassContainsTheFlagsForTheInnerMethods() throws IOException, ClassNotFoundException,
+ NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ ManipulatedClassLoader classLoader = manipulate(className, manipulator);
+
+ Class clazz = classLoader.findClass(className);
+
+ String flag = "__M" + "MyInnerWithANativeMethod" + "___" + "foo";
+ assertThat(clazz.getDeclaredField(flag)).isNotNull();
+
+ flag = "__M" + "MyInnerClass" + "___" + "foo";
+ assertThat(clazz.getDeclaredField(flag)).isNotNull();
+
+ flag = "__M" + "1" + "___" + "compute" + "$java_lang_String";
+ assertThat(clazz.getDeclaredField(flag)).isNotNull();
+ }
+
+ @Test
+ public void testThatStaticInnerClassesAreNotManipulated() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ ManipulatedClassLoader classLoader = manipulate(className, manipulator);
+
+ Class clazz = classLoader.findClass(className);
+ Class inner = findInnerClass(clazz.getClasses(), "MyStaticInnerClass");
+ assertThat(inner).isNotNull();
+ Method bar = inner.getMethod("bar");
+ Object o = inner.newInstance();
+ bar.setAccessible(true);
+ assertThat(bar).isNotNull();
+ assertThat((String) bar.invoke(o)).isEqualTo("bar");
+ }
+
+ @Test
+ public void testThatAnonymousClassDeclaredInStaticFieldsAreNotManipulated() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ String className = "test.inner.ComponentWithInnerClasses";
+ ManipulatedClassLoader classLoader = manipulate(className, manipulator);
+
+ Class clazz = classLoader.findClass(className);
+ Method method = clazz.getMethod("call");
+ assertThat(method).isNotNull();
+ assertThat(method.invoke(null)).isEqualTo(1);
+ }
+
+ private Class findInnerClass(Class[] classes, String name) {
+ for (Class clazz : classes) {
+ if (clazz.getName().contains(name)) {
+ return clazz;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatedClassLoader.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatedClassLoader.java
new file mode 100644
index 0000000..1aa8ce4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatedClassLoader.java
@@ -0,0 +1,97 @@
+/*
+ * 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.manipulation;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A classloader used to load manipulated classes.
+ */
+public class ManipulatedClassLoader extends ClassLoader {
+
+ private String name;
+ private byte[] clazz;
+
+ private Map<String, byte[]> inner = new LinkedHashMap<String, byte[]>();
+
+ public ManipulatedClassLoader(String name, byte[] clazz) {
+ this.name = name;
+ this.clazz = clazz;
+ }
+
+ public byte[] get(String name) {
+ if (name.equals(this.name)) {
+ return clazz;
+ }
+ if (inner.containsKey(name)) {
+ return inner.get(name);
+ }
+ return null;
+ }
+
+ public void addInnerClass(String name, byte[] clazz) {
+ inner.put(name, clazz);
+ }
+
+ public Class findClass(String name) throws ClassNotFoundException {
+ if (name.equals(this.name)) {
+ return defineClass(name, clazz, 0, clazz.length);
+ }
+
+ if (inner.containsKey(name)) {
+ return defineClass(name, inner.get(name), 0, inner.get(name).length);
+ }
+
+ return super.findClass(name);
+ }
+
+ public Class loadClass(String classname) throws ClassNotFoundException {
+ if (inner.containsKey(classname)) {
+ return findClass(classname);
+ }
+ return super.loadClass(classname);
+ }
+
+ public static final File DUMP_BASEDIR = new File("target/dump");
+
+ public void dump() throws IOException {
+ File outer = new File(DUMP_BASEDIR, name.replace(".", "/") + ".class");
+ FileUtils.writeByteArrayToFile(outer, clazz);
+ for (String name : inner.keySet()) {
+ File file = new File(DUMP_BASEDIR, name.replace(".", "/") + ".class");
+ FileUtils.writeByteArrayToFile(file, inner.get(name));
+ }
+ }
+
+ public Map<String, byte[]> getAllInnerClasses() {
+ return inner;
+ }
+
+ public void addInnerClassIfNotAlreadyDefined(String name, byte[] innerClassBytecode) {
+ if (! inner.containsKey(name)) {
+ inner.put(name, innerClassBytecode);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
new file mode 100644
index 0000000..03f9b4a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
@@ -0,0 +1,460 @@
+/*
+ * 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.manipulation;
+
+import java.io.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Pojo;
+import org.junit.Ignore;
+import org.mockito.Mockito;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.util.CheckClassAdapter;
+
+public class ManipulatorTest extends TestCase {
+
+ public void testClusterDaemon() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ClusterDaemon", clazz);
+
+ //Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ //System.out.println(manipulator.getManipulationMetadata());
+
+
+ ClassReader reader = new ClassReader(clazz);
+ CheckClassAdapter.verify(reader, false, new PrintWriter(new File("/tmp/class_dump")));
+
+ Class cl = classloader.findClass("test.ClusterDaemon");
+ //Assert.assertNotNull(cl);
+
+ // The manipulation add stuff to the class.
+ //Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")).length);
+
+ //Assert.assertNotNull(cl.newInstance());
+
+ }
+
+ public void testCrypto() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/frames/CryptoServiceSingleton.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.frames.CryptoServiceSingleton", clazz);
+
+ //Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ //System.out.println(manipulator.getManipulationMetadata());
+
+
+ ClassReader reader = new ClassReader(clazz);
+ CheckClassAdapter.verify(reader, false, new PrintWriter(new File("/tmp/class_dump")));
+
+ Class cl = classloader.findClass("test.frames.CryptoServiceSingleton");
+ Assert.assertNotNull(cl);
+
+ Object instance = cl.newInstance();
+
+ Method method = cl.getMethod("encryptAESWithCBC", String.class, String.class);
+ final String salt = "0000000000000000";
+ String result = (String) method.invoke(instance, "hello", salt);
+ assertNotNull(result);
+
+ // The manipulation add stuff to the class.
+ //Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")).length);
+
+ //Assert.assertNotNull(cl.newInstance());
+
+ }
+
+ public void testManipulatingTheSimplePojo() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/SimplePojo.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.SimplePojo", clazz);
+ Class cl = classloader.findClass("test.SimplePojo");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ System.out.println(manipulator.getManipulationMetadata());
+
+ // The manipulation add stuff to the class.
+ Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")).length);
+
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // We still have the empty constructor
+ found = false;
+ csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 0) {
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ Method method = cl.getMethod("doSomething", new Class[0]);
+ Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+ }
+
+ public void testManipulatingTheNonSunPOJO() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/NonSunClass.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.NonSunClass", clazz);
+ Class cl = classloader.findClass("test.NonSunClass");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ System.out.println(manipulator.getManipulationMetadata());
+
+ // The manipulation add stuff to the class.
+ Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/NonSunClass.class")).length);
+
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ Method method = cl.getMethod("getS1", new Class[0]);
+ Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+ }
+
+ public void testManipulatingChild() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/Child.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz);
+ Class cl = classloader.findClass("test.Child");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // We still have the regular constructor
+ found = false;
+ csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 2) {
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {im});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ Method method = cl.getMethod("doSomething", new Class[0]);
+ Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+ }
+
+ public void testManipulatingWithConstructorModification() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/Child.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz);
+ Class cl = classloader.findClass("test.Child");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // We still have the regular constructor
+ found = false;
+ csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 2) {
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check that we have the IM, Integer, String constructor too
+ Constructor cst2 = cl.getDeclaredConstructor(new Class[] { InstanceManager.class, Integer.TYPE, String.class });
+ Assert.assertNotNull(cst2);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+
+ // Creation using cst
+ InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {im});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ Method method = cl.getMethod("doSomething", new Class[0]);
+ Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+ // Try to create using cst2
+ im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ cst2.setAccessible(true);
+ pojo = cst2.newInstance(new Object[] {im, new Integer(2), "bariton"});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ method = cl.getMethod("doSomething", new Class[0]);
+ Assert.assertEquals(10, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+
+
+ }
+
+
+ public void testManipulatingWithNoValidConstructor() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.NoValidConstructor", clazz);
+ Class cl = classloader.findClass("test.NoValidConstructor");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ System.out.println(manipulator.getManipulationMetadata());
+
+ // The manipulation add stuff to the class.
+ Assert.assertTrue(clazz.length > origin.length);
+
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ }
+
+ public void testConstructor() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/ConstructorCheck.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+
+// File out = new File("target/ManipulatedConstructorCheck.class");
+// FileOutputStream fos = new FileOutputStream(out);
+// fos.write(clazz);
+// fos.close();
+
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ConstructorCheck", clazz);
+ Class cl = classloader.findClass("test.ConstructorCheck");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ System.out.println(manipulator.getManipulationMetadata());
+
+ Constructor c = cl.getConstructor(new Class[] {String.class });
+ Assert.assertNotNull(c);
+
+ Object o = c.newInstance("toto");
+ Field f = o.getClass().getField("m_foo");
+ Assert.assertEquals("toto", f.get(o));
+ }
+
+ /**
+ * https://issues.apache.org/jira/browse/FELIX-3621
+ */
+ public void testManipulatingDoubleArray() throws Exception {
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ byte[] origin = getBytesFromFile(new File("target/test-classes/test/DoubleArray.class"));
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.DoubleArray", clazz);
+ Class cl = classloader.findClass("test.DoubleArray");
+ Assert.assertNotNull(cl);
+ Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+ System.out.println(manipulator.getManipulationMetadata());
+ Assert.assertTrue(manipulator.getManipulationMetadata().toString().contains("arguments=\"{int[][]}\""));
+
+ // The manipulation add stuff to the class.
+ Assert.assertTrue(clazz.length > origin.length);
+
+
+ boolean found = false;
+ Constructor cst = null;
+ Constructor[] csts = cl.getDeclaredConstructors();
+ for(int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 1 &&
+ csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+ found = true;
+ cst = csts[i];
+ }
+ }
+ Assert.assertTrue(found);
+
+ // We still have the empty constructor
+ found = false;
+ csts = cl.getDeclaredConstructors();
+ for (int i = 0; i < csts.length; i++) {
+ System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+ if (csts[i].getParameterTypes().length == 0) {
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+
+ // Check the POJO interface
+ Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+ cst.setAccessible(true);
+ Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+ Assert.assertNotNull(pojo);
+ Assert.assertTrue(pojo instanceof Pojo);
+
+ Method method = cl.getMethod("start", new Class[0]);
+ Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+ }
+
+
+
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+ long length = file.length();
+ byte[] bytes = new byte[(int)length];
+
+ // Read in the bytes
+ int offset = 0;
+ int numRead = 0;
+ while (offset < bytes.length
+ && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+ offset += numRead;
+ }
+
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException("Could not completely read file "+file.getName());
+ }
+
+ // Close the input stream and return bytes
+ is.close();
+ return bytes;
+ }
+
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
new file mode 100644
index 0000000..0e50111
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.manipulation;
+
+import java.io.File;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+
+public class PojoizationTest extends TestCase {
+
+ public void testJarManipulation() {
+ Pojoization pojoization = new Pojoization();
+ pojoization.setUseLocalXSD();
+ File in = new File("target/test-classes/tests.manipulation-no-annotations.jar");
+ File out = new File("target/test-classes/tests.manipulation-no-annotations-manipulated.jar");
+ out.delete();
+ File metadata = new File("target/test-classes/metadata.xml");
+ pojoization.pojoization(in, out, metadata, null);
+
+ Assert.assertTrue(out.exists());
+ }
+
+ public void testManipulationWithAnnotations() {
+ Pojoization pojoization = new Pojoization();
+ pojoization.setUseLocalXSD();
+ File in = new File("target/test-classes/tests.manipulator-annotations.jar");
+ File out = new File("target/test-classes/tests.manipulation-annotations-manipulated.jar");
+ out.delete();
+ pojoization.pojoization(in, out, (File) null, null);
+
+ Assert.assertTrue(out.exists());
+ }
+
+ public void testJarManipulationJava5() {
+ Pojoization pojoization = new Pojoization();
+ pojoization.setUseLocalXSD();
+ File in = new File("target/test-classes/tests.manipulation.java5.jar");
+ File out = new File("target/test-classes/tests.manipulation.java5-manipulated.jar");
+ out.delete();
+ pojoization.pojoization(in, out, (File) null, null);
+
+ Assert.assertTrue(out.exists());
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/RemanipulationTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/RemanipulationTest.java
new file mode 100644
index 0000000..0e0c556
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/RemanipulationTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.manipulation;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.AnnotationMetadataProvider;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Test Case for FELIX-3461.
+ * Checks the consistency of multiple manipulation.
+ */
+public class RemanipulationTest extends TestCase {
+
+ /**
+ * Tests checking that the consecutive manipulation does still returns valid metadata (from annotations),
+ * and valid manipulation metadata.
+ *
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ public void testDoubleManipulationWithAnnotations() throws IOException, ClassNotFoundException {
+ Reporter reporter = mock(Reporter.class);
+ // Step 1 - First collection and manipulation
+ //1.1 Metadata collection
+ byte[] origin = ManipulatorTest.getBytesFromFile(new File("target/test-classes/test/PlentyOfAnnotations.class"));
+ MiniStore store = new MiniStore()
+ .addClassToStore("test.PlentyOfAnnotations",
+ origin);
+ AnnotationMetadataProvider provider = new AnnotationMetadataProvider(store, reporter);
+ List<Element> originalMetadata = provider.getMetadatas();
+ // 1.2 Manipulation
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ manipulator.prepare(origin);
+ byte[] clazz = manipulator.manipulate(origin);
+ Element originalManipulationMetadata = manipulator.getManipulationMetadata();
+ // 1.3 Check that the class is valid
+ ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.PlentyOfAnnotations", clazz);
+ Class cl = classloader.findClass("test.PlentyOfAnnotations");
+ Assert.assertNotNull(cl);
+
+ // ---------------
+
+ // Step 2 - Second collection and manipulation
+ // We use the output class as entry.
+ // 2.1 Metadata collection
+ store = new MiniStore().addClassToStore("test.PlentyOfAnnotations", clazz);
+ provider = new AnnotationMetadataProvider(store, reporter);
+ List<Element> metadataAfterOneManipulation = provider.getMetadatas();
+ // 2.2 Manipulation
+ manipulator = new Manipulator(this.getClass().getClassLoader());
+ manipulator.prepare(clazz);
+ byte[] clazz2 = manipulator.manipulate(clazz);
+ Element manipulationMetadataAfterSecondManipulation = manipulator.getManipulationMetadata();
+ // 2.3 Check that the class is valid
+ classloader = new ManipulatedClassLoader("test.PlentyOfAnnotations", clazz);
+ cl = classloader.findClass("test.PlentyOfAnnotations");
+ Assert.assertNotNull(cl);
+
+ // ---------------
+
+ // Step 3 - Third collection and manipulation
+ // We use the output class of 2 as entry.
+ // 3.1 Metadata collection
+ store = new MiniStore().addClassToStore("test.PlentyOfAnnotations", clazz2);
+ provider = new AnnotationMetadataProvider(store, reporter);
+ List<Element> metadataAfterTwoManipulation = provider.getMetadatas();
+ // 3.2 Manipulation
+ manipulator = new Manipulator(this.getClass().getClassLoader());
+ manipulator.prepare(clazz2);
+ byte[] clazz3 = manipulator.manipulate(clazz2);
+ Element manipulationMetadataAfterThirdManipulation = manipulator.getManipulationMetadata();
+ // 3.3 Check that the class is valid
+ classloader = new ManipulatedClassLoader("test.PlentyOfAnnotations", clazz);
+ cl = classloader.findClass("test.PlentyOfAnnotations");
+ Assert.assertNotNull(cl);
+
+ // ---------------
+ // Verification
+
+ // Unchanged metadata
+ Assert.assertEquals(originalMetadata.toString(), metadataAfterOneManipulation.toString());
+ Assert.assertEquals(originalMetadata.toString(), metadataAfterTwoManipulation.toString());
+
+ // Unchanged manipulation metadata
+ Assert.assertEquals(originalManipulationMetadata.toString(),
+ manipulationMetadataAfterSecondManipulation.toString());
+ Assert.assertEquals(originalManipulationMetadata.toString(),
+ manipulationMetadataAfterThirdManipulation.toString());
+
+ }
+
+ private class MiniStore implements ResourceStore {
+
+ private Map<String, byte[]> resources;
+
+ public MiniStore addClassToStore(String qualifiedName, byte[] bytes) {
+ if (this.resources == null) {
+ this.resources = new HashMap<String, byte[]>();
+ }
+ this.resources.put(Strings.asResourcePath(qualifiedName), bytes);
+ return this;
+ }
+
+ public byte[] read(String path) throws IOException {
+ byte[] bytes = resources.get(path);
+ if (bytes == null) {
+ throw new IOException();
+ }
+ return bytes;
+ }
+
+ public void accept(ResourceVisitor visitor) {
+ for (Map.Entry<String, byte[]> entry : resources.entrySet()) {
+ visitor.visit(entry.getKey());
+ }
+ }
+
+ public void open() throws IOException {
+ }
+
+ public void writeMetadata(Element metadata) {
+ }
+
+ public void write(String resourcePath, byte[] resource) throws IOException {
+ }
+
+ public void close() throws IOException {
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java
new file mode 100644
index 0000000..8166ac5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java
@@ -0,0 +1,113 @@
+/*
+ * 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.manipulator;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import test.ClusterDaemon;
+import test.PojoWithInner;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ManipulationEngineTestCase extends TestCase {
+
+ @Mock
+ private Reporter reporter;
+
+ @Mock
+ private ResourceStore store;
+
+ @Mock
+ private ManipulationVisitor visitor;
+
+ @Mock
+ private ManipulationResultVisitor result;
+
+ @InjectMocks
+ private ManipulationEngine engine = new ManipulationEngine(this.getClass().getClassLoader());
+
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testManipulationOfSimpleClass() throws Exception {
+
+ when(store.read(anyString())).thenReturn(from(ClusterDaemon.class));
+ when(visitor.visitManipulationResult(any(Element.class))).thenReturn(result);
+
+ String path = Strings.asResourcePath(ClusterDaemon.class.getName());
+ Element metadata = new Element("", "");
+ ManipulationUnit info = new ManipulationUnit(path, metadata);
+ engine.addManipulationUnit(info);
+
+ engine.generate();
+
+ verify(visitor).visitManipulationResult(eq(metadata));
+ verify(result).visitClassStructure(any(Element.class));
+ verify(result).visitManipulatedResource(eq(path), any(byte[].class));
+ verify(result).visitEnd();
+
+ }
+
+ public void testManipulationOfInnerClass() throws Exception {
+
+ when(visitor.visitManipulationResult(any(Element.class))).thenReturn(result);
+
+ String innerPath = Strings.asResourcePath(PojoWithInner.MyInner.class.getName());
+ when(store.read(innerPath)).thenReturn(from(PojoWithInner.MyInner.class));
+
+ String path = Strings.asResourcePath(PojoWithInner.class.getName());
+ when(store.read(path)).thenReturn(from(PojoWithInner.class));
+
+ Element metadata = new Element("", "");
+ ManipulationUnit info = new ManipulationUnit(path, metadata);
+ engine.addManipulationUnit(info);
+
+ engine.generate();
+
+ verify(visitor).visitManipulationResult(eq(metadata));
+ verify(result).visitClassStructure(any(Element.class));
+ verify(result).visitManipulatedResource(eq(path), any(byte[].class));
+ verify(result).visitManipulatedResource(eq(innerPath), any(byte[].class));
+ verify(result).visitEnd();
+
+ }
+
+ private byte[] from(Class<?> type) throws IOException {
+ ClassLoader loader = type.getClassLoader();
+ InputStream is = loader.getResourceAsStream(Strings.asResourcePath(type.getName()));
+ return Streams.readBytes(is);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java
new file mode 100644
index 0000000..6df1bb7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java
@@ -0,0 +1,33 @@
+/*
+ * 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.manipulator.manifest;
+
+import junit.framework.TestCase;
+
+import java.util.jar.Manifest;
+
+public class DirectManifestProviderTestCase extends TestCase {
+ public void testGetManifest() throws Exception {
+ Manifest origin = new Manifest();
+ DirectManifestProvider provider = new DirectManifestProvider(origin);
+
+ assertSame(origin, provider.getManifest());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java
new file mode 100644
index 0000000..bb96b0e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java
@@ -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.manipulator.manifest;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.jar.Manifest;
+
+public class FileManifestProviderTestCase extends TestCase {
+ public void testGetManifest() throws Exception {
+ File manifestFile = new File(new File("target", "test-classes"), "MANIFEST.MF");
+ FileManifestProvider provider = new FileManifestProvider(manifestFile);
+
+ Manifest manifest = provider.getManifest();
+
+ assertNotNull(manifest);
+ assertEquals("tests.manipulation.java5", manifest.getMainAttributes().getValue("Bundle-SymbolicName"));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java
new file mode 100644
index 0000000..d469495
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java
@@ -0,0 +1,94 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+import test.AnnotatedComponent;
+import test.FakeAnnotation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+
+public class AnnotationMetadataProviderTestCase extends TestCase {
+ public void testGetMetadatas() throws Exception {
+ MiniStore store = new MiniStore(AnnotatedComponent.class, FakeAnnotation.class);
+ Reporter reporter = mock(Reporter.class);
+ AnnotationMetadataProvider provider = new AnnotationMetadataProvider(store, reporter);
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(1, meta.size());
+
+
+ }
+
+ private class MiniStore implements ResourceStore {
+
+ private Map<String, byte[]> resources;
+
+ public MiniStore(Class<?>... classes) throws IOException {
+ this.resources = new HashMap<String, byte[]>();
+ for (Class<?> type : classes) {
+ resources.put(Strings.asResourcePath(type.getName()), from(type));
+ }
+ }
+
+ public byte[] read(String path) throws IOException {
+ byte[] bytes = resources.get(path);
+ if (bytes == null) {
+ throw new IOException();
+ }
+ return bytes;
+ }
+
+ public void accept(ResourceVisitor visitor) {
+ for (Map.Entry<String, byte[]> entry : resources.entrySet()) {
+ visitor.visit(entry.getKey());
+ }
+ }
+
+ public void open() throws IOException {}
+
+ public void writeMetadata(Element metadata) {}
+
+ public void write(String resourcePath, byte[] resource) throws IOException {}
+
+ public void close() throws IOException {}
+ }
+
+ private byte[] from(Class<?> type) throws IOException {
+ ClassLoader loader = type.getClassLoader();
+ InputStream is = loader.getResourceAsStream(Strings.asResourcePath(type.getName()));
+ return Streams.readBytes(is);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java
new file mode 100644
index 0000000..4f423f5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.Collections;
+
+import static org.mockito.Mockito.*;
+
+public class CacheableMetadataProviderTestCase extends TestCase {
+ public void testGetMetadatas() throws Exception {
+ MetadataProvider delegate = mock(MetadataProvider.class);
+ CacheableMetadataProvider provider = new CacheableMetadataProvider(delegate);
+
+ Element returned = new Element("test", null);
+ when(delegate.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+ provider.getMetadatas();
+ provider.getMetadatas();
+ provider.getMetadatas();
+ provider.getMetadatas();
+
+ verify(delegate, atMost(1)).getMetadatas();
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java
new file mode 100644
index 0000000..96367ad
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java
@@ -0,0 +1,112 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+
+public class CompositeMetadataProviderTestCase extends TestCase {
+
+ @Mock
+ private MetadataProvider delegate1;
+
+ @Mock
+ private MetadataProvider delegate2;
+
+ @Mock
+ private Reporter reporter;
+
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testGetMetadatas() throws Exception {
+ CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+ provider.addMetadataProvider(delegate1);
+ provider.addMetadataProvider(delegate2);
+
+ Element returned = newComponentElement("type1");
+ when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+ Element returned2 = newComponentElement("type2");
+ when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(2, meta.size());
+ }
+
+ public void testGetMetadatasWithDuplicate() throws Exception {
+ CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+ provider.addMetadataProvider(delegate1);
+ provider.addMetadataProvider(delegate2);
+
+ Element returned = newComponentElement("type1");
+ when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+ Element returned2 = newComponentElement("type1");
+ when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(1, meta.size());
+
+ verify(reporter).warn(anyString());
+ }
+
+ public void testGetMetadatasWithInstances() throws Exception {
+ CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+ provider.addMetadataProvider(delegate1);
+ provider.addMetadataProvider(delegate2);
+
+ Element returned = newInstanceElement("type1", "name1");
+ when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+ // Try with a duplicate instance name
+ Element returned2 = newInstanceElement("type1", "name2");
+ when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(2, meta.size());
+ }
+
+ private Element newComponentElement(String type) {
+ Element main = new Element("component", null);
+ main.addAttribute(new Attribute("name", type));
+ return main;
+ }
+
+ private Element newInstanceElement(String type, String name) {
+ Element main = new Element("instance", null);
+ main.addAttribute(new Attribute("component", type));
+ main.addAttribute(new Attribute("name", name));
+ return main;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java
new file mode 100644
index 0000000..d61604b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java
@@ -0,0 +1,29 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+
+public class EmptyMetadataProviderTestCase extends TestCase {
+ public void testGetMetadatas() throws Exception {
+ EmptyMetadataProvider provider = new EmptyMetadataProvider();
+ assertTrue(provider.getMetadatas().isEmpty());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java
new file mode 100644
index 0000000..47a16dd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java
@@ -0,0 +1,51 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+public class FileMetadataProviderTestCase extends TestCase {
+ public void testGetMetadatasFromFile() throws Exception {
+ File metadata = new File(new File("target", "test-classes"), "metadata.xml");
+ Reporter reporter = mock(Reporter.class);
+ FileMetadataProvider provider = new FileMetadataProvider(metadata, reporter);
+ provider.setValidateUsingLocalSchemas(true);
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(3, meta.size());
+ }
+
+ public void testGetMetadatasFromDirectory() throws Exception {
+ File metadata = new File("target", "test-classes");
+ Reporter reporter = mock(Reporter.class);
+ FileMetadataProvider provider = new FileMetadataProvider(metadata, reporter);
+ provider.setValidateUsingLocalSchemas(true);
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(3, meta.size());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java
new file mode 100644
index 0000000..c8a67da
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java
@@ -0,0 +1,60 @@
+/*
+ * 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.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class StreamMetadataProviderTestCase extends TestCase {
+
+ public void testGetMetadatas() throws Exception {
+ File metadata = new File(new File("target", "test-classes"), "metadata.xml");
+ FileInputStream fis = new FileInputStream(metadata);
+ Reporter reporter = mock(Reporter.class);
+
+ StreamMetadataProvider provider = new StreamMetadataProvider(fis, reporter);
+ provider.setValidateUsingLocalSchemas(true);
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(3, meta.size());
+ }
+
+ public void testWithEmptyMetadataXml() throws Exception {
+ File metadata = new File(new File("target", "test-classes"), "empty-metadata.xml");
+ FileInputStream fis = new FileInputStream(metadata);
+ Reporter reporter = mock(Reporter.class);
+
+ StreamMetadataProvider provider = new StreamMetadataProvider(fis, reporter);
+ provider.setValidateUsingLocalSchemas(true);
+
+ List<Element> meta = provider.getMetadatas();
+ assertEquals(0, meta.size());
+ verify(reporter).warn(anyString());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java
new file mode 100644
index 0000000..4283055
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java
@@ -0,0 +1,90 @@
+/*
+ * 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.manipulator.metadata.annotation;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.ClassNode;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/12/12
+ * Time: 11:17 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ComponentWorkbenchTestCase extends TestCase {
+ public void testBuildWithNoTopLevelElements() throws Exception {
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ Element built = workbench.build();
+ assertNull(built);
+
+ }
+
+ public void testSimpleBuild() throws Exception {
+
+ Element root = new Element("root", null);
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ workbench.setRoot(root);
+ Element built = workbench.build();
+
+ assertEquals("root", built.getName());
+ assertNull(built.getNameSpace());
+ assertEquals(0, built.getAttributes().length);
+ assertEquals(0, built.getElements().length);
+
+ }
+
+ public void testElementsAreHierarchicallyPlaced() throws Exception {
+
+ Element root = new Element("root", null);
+ Element child = new Element("child", null);
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ workbench.setRoot(root);
+ workbench.getElements().put(child, null);
+
+ Element built = workbench.build();
+
+ assertEquals("root", built.getName());
+ assertNull(built.getNameSpace());
+ assertEquals(0, built.getAttributes().length);
+ assertEquals(1, built.getElements().length);
+
+ Element builtChild = built.getElements("child")[0];
+
+ assertEquals("child", builtChild.getName());
+ assertNull(builtChild.getNameSpace());
+ assertEquals(0, builtChild.getAttributes().length);
+ assertEquals(0, builtChild.getElements().length);
+
+
+ }
+
+
+ public static ClassNode node() {
+ ClassNode node = new ClassNode();
+ node.name = "my/Component";
+ return node;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlaybackTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlaybackTestCase.java
new file mode 100644
index 0000000..05c1c68
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/AnnotationPlaybackTestCase.java
@@ -0,0 +1,196 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.AnnotationPlayback;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.AnnotationAnnotation;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.ArrayAnnotation;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.EnumAnnotation;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.InnerAnnotation;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.Mode;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.SimpleTypes;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.model.literal.types.Support;
+import org.mockito.Mock;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Type;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 08/07/13
+ * Time: 17:25
+ */
+
+public class AnnotationPlaybackTestCase extends TestCase {
+
+ @Mock
+ private ClassVisitor visitor;
+
+ @Mock
+ private AnnotationVisitor annotationVisitor;
+
+ @Mock
+ private AnnotationVisitor arrayVisitor;
+
+ @Mock
+ private AnnotationVisitor innerAnnotationVisitor;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testSimpleValuesPlayback() throws Exception {
+
+ when(visitor.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor);
+
+ AnnotationPlayback playback = new AnnotationPlayback(find(SimpleTypes.class));
+ playback.accept(visitor);
+
+ verify(visitor).visitAnnotation(Type.getType(SimpleTypes.class).getDescriptor(),
+ true);
+ verify(annotationVisitor).visitEnd();
+
+ // Verify simple mono-valued attributes
+ verify(annotationVisitor).visit("aByte", Byte.valueOf((byte) 42));
+ verify(annotationVisitor).visit("aBoolean", Boolean.TRUE);
+ verify(annotationVisitor).visit("anInt", Integer.valueOf(42));
+ verify(annotationVisitor).visit("aLong", Long.valueOf(42));
+ verify(annotationVisitor).visit("aShort", Short.valueOf((short) 42));
+ verify(annotationVisitor).visit("aFloat", Float.valueOf(42));
+ verify(annotationVisitor).visit("aDouble", Double.valueOf(42));
+ verify(annotationVisitor).visit("aChar", Character.valueOf('a'));
+
+ // Verify String & Class
+ verify(annotationVisitor).visit("aString", "42");
+ verify(annotationVisitor).visit("aClass", Type.getType(String.class));
+
+ // Verify array os simple types
+ verify(annotationVisitor).visit("arrayOfByte", new byte[] {(byte) 42});
+ verify(annotationVisitor).visit("arrayOfBoolean", new boolean[] {true, true});
+ verify(annotationVisitor).visit("arrayOfInt", new int[] {42});
+ verify(annotationVisitor).visit("arrayOfLong", new long[] {42});
+ verify(annotationVisitor).visit("arrayOfShort", new short[] {42});
+ verify(annotationVisitor).visit("arrayOfFloat", new float[] {42});
+ verify(annotationVisitor).visit("arrayOfDouble", new double[] {});
+ verify(annotationVisitor).visit("arrayOfChar", new char[] {'a', 'b', 'c'});
+
+ }
+
+ public void testEnumValuesPlayback() throws Exception {
+
+ when(visitor.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor);
+
+ AnnotationPlayback playback = new AnnotationPlayback(find(EnumAnnotation.class));
+ playback.accept(visitor);
+
+ verify(visitor).visitAnnotation(Type.getType(EnumAnnotation.class).getDescriptor(),
+ true);
+ verify(annotationVisitor).visitEnd();
+
+ String desc = Type.getType(Mode.class).getDescriptor();
+ verify(annotationVisitor).visitEnum("noDefault", desc, "IN");
+ verify(annotationVisitor).visitEnum("withDefault", desc, "IN");
+ verify(annotationVisitor).visitEnum("withDefaultOverridden", desc, "IN");
+ }
+
+ public void testArrayValuesPlayback() throws Exception {
+
+ AnnotationVisitor arrayOfString = mock(AnnotationVisitor.class);
+ AnnotationVisitor arrayOfEnum = mock(AnnotationVisitor.class);
+ AnnotationVisitor arrayOfClass = mock(AnnotationVisitor.class);
+ AnnotationVisitor arrayOfAnnotation = mock(AnnotationVisitor.class);
+ AnnotationVisitor emptyArray = mock(AnnotationVisitor.class);
+
+ when(visitor.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor);
+ when(annotationVisitor.visitArray("arrayOfString")).thenReturn(arrayOfString);
+ when(annotationVisitor.visitArray("arrayOfEnum")).thenReturn(arrayOfEnum);
+ when(annotationVisitor.visitArray("arrayOfClass")).thenReturn(arrayOfClass);
+ when(annotationVisitor.visitArray("arrayOfAnnotation")).thenReturn(arrayOfAnnotation);
+ when(annotationVisitor.visitArray("emptyArray")).thenReturn(emptyArray);
+
+ AnnotationPlayback playback = new AnnotationPlayback(find(ArrayAnnotation.class));
+ playback.accept(visitor);
+
+ verify(visitor).visitAnnotation(Type.getType(ArrayAnnotation.class).getDescriptor(),
+ true);
+ verify(annotationVisitor).visitEnd();
+
+ String desc = Type.getType(Mode.class).getDescriptor();
+
+ verify(arrayOfString).visit(null, "42");
+ verify(arrayOfString).visit(null, "43");
+ verify(arrayOfString).visitEnd();
+
+ verify(arrayOfEnum).visitEnum(null, desc, "IN");
+ verify(arrayOfEnum).visitEnd();
+
+ verify(arrayOfClass).visit(null, Type.getType(Object.class));
+ verify(arrayOfClass).visitEnd();
+
+ verify(arrayOfAnnotation).visitAnnotation(null, Type.getType(InnerAnnotation.class).getDescriptor());
+ verify(arrayOfAnnotation).visitEnd();
+
+ verify(emptyArray).visitEnd();
+
+ }
+
+
+ public void testAnnotationValuesPlayback() throws Exception {
+
+ when(visitor.visitAnnotation(anyString(), anyBoolean())).thenReturn(annotationVisitor);
+ when(annotationVisitor.visitAnnotation("value", Type.getType(InnerAnnotation.class).getDescriptor()))
+ .thenReturn(innerAnnotationVisitor);
+ when(innerAnnotationVisitor.visitArray("arrayOfClass"))
+ .thenReturn(arrayVisitor);
+
+ AnnotationPlayback playback = new AnnotationPlayback(find(AnnotationAnnotation.class));
+ playback.accept(visitor);
+
+ verify(visitor).visitAnnotation(Type.getType(AnnotationAnnotation.class).getDescriptor(),
+ true);
+ verify(annotationVisitor).visitEnd();
+
+ String desc = Type.getType(Mode.class).getDescriptor();
+ verify(innerAnnotationVisitor).visit("aString", "42");
+ verify(innerAnnotationVisitor).visitEnum("modeEnum", desc, "IN");
+ verify(innerAnnotationVisitor).visitEnd();
+
+ verify(arrayVisitor).visit(null, Type.getType(Object.class));
+ verify(arrayVisitor).visitEnd();
+
+ }
+ private Annotation find(final Class<? extends Annotation> type) {
+ return Support.class.getAnnotation(type);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/AnnotationAnnotation.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/AnnotationAnnotation.java
new file mode 100644
index 0000000..c707d7d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/AnnotationAnnotation.java
@@ -0,0 +1,36 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 10:15
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationAnnotation {
+ InnerAnnotation value();
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/ArrayAnnotation.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/ArrayAnnotation.java
new file mode 100644
index 0000000..92bee87
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/ArrayAnnotation.java
@@ -0,0 +1,40 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 10:15
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ArrayAnnotation {
+ String[] arrayOfString();
+ Class<?>[] arrayOfClass();
+ Mode[] arrayOfEnum();
+ InnerAnnotation[] arrayOfAnnotation();
+ Mode[] emptyArray() default {};
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/EnumAnnotation.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/EnumAnnotation.java
new file mode 100644
index 0000000..9ec1a4a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/EnumAnnotation.java
@@ -0,0 +1,38 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 10:15
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnumAnnotation {
+ Mode noDefault();
+ Mode withDefault() default Mode.IN;
+ Mode withDefaultOverridden() default Mode.OUT;
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/InnerAnnotation.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/InnerAnnotation.java
new file mode 100644
index 0000000..4bdfbd7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/InnerAnnotation.java
@@ -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.manipulator.metadata.annotation.model.literal.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 10:15
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InnerAnnotation {
+ String aString() default "42";
+ Class[] arrayOfClass() default {};
+ Mode modeEnum() default Mode.IN;
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Mode.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Mode.java
new file mode 100644
index 0000000..dec0af2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Mode.java
@@ -0,0 +1,29 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal.types;
+
+/**
+ * User: guillaume
+ * Date: 09/07/13
+ * Time: 10:14
+ */
+public enum Mode {
+ IN, OUT
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/SimpleTypes.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/SimpleTypes.java
new file mode 100644
index 0000000..c592962
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/SimpleTypes.java
@@ -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.felix.ipojo.manipulator.metadata.annotation.model.literal.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+* User: guillaume
+* Date: 08/07/13
+* Time: 17:37
+*/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SimpleTypes {
+ boolean aBoolean() default true;
+ byte aByte() default 42;
+ long aLong() default 42;
+ int anInt() default 42;
+ short aShort() default 42;
+ float aFloat() default 42;
+ double aDouble() default 42;
+ char aChar() default 'a';
+
+ String aString() default "42";
+ Class<?> aClass() default String.class;
+
+ boolean[] arrayOfBoolean() default {true, true};
+ byte[] arrayOfByte() default {42};
+ long[] arrayOfLong() default {42};
+ int[] arrayOfInt() default {42};
+ short[] arrayOfShort() default {42};
+ float[] arrayOfFloat() default 42;
+ double[] arrayOfDouble() default {};
+ char[] arrayOfChar() default {'a', 'b', 'c'};
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Support.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Support.java
new file mode 100644
index 0000000..3c2bee6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/literal/types/Support.java
@@ -0,0 +1,44 @@
+/*
+ * 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.manipulator.metadata.annotation.model.literal.types;
+
+/**
+ * User: guillaume
+ * Date: 08/07/13
+ * Time: 17:36
+ */
+@SimpleTypes
+@EnumAnnotation(
+ noDefault = Mode.IN,
+ withDefaultOverridden = Mode.IN
+)
+@ArrayAnnotation(
+ arrayOfString = {"42", "43"},
+ arrayOfEnum = Mode.IN,
+ arrayOfClass = Object.class,
+ arrayOfAnnotation = @InnerAnnotation()
+)
+@AnnotationAnnotation(
+ @InnerAnnotation(
+ arrayOfClass = Object.class
+ )
+)
+public class Support {
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorderTestCase.java
new file mode 100644
index 0000000..fdd9244
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/model/parser/replay/AnnotationRecorderTestCase.java
@@ -0,0 +1,92 @@
+/*
+ * 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.manipulator.metadata.annotation.model.parser.replay;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.AnnotationVisitor;
+
+import junit.framework.TestCase;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * User: guillaume
+ * Date: 30/05/13
+ * Time: 22:04
+ */
+public class AnnotationRecorderTestCase extends TestCase {
+
+ @Mock
+ private AnnotationVisitor visitor;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testVisitRecord() throws Exception {
+ AnnotationRecorder recorder = new AnnotationRecorder();
+ recorder.visit("attribute", "a value");
+ recorder.accept(visitor);
+ verify(visitor).visit("attribute", "a value");
+ }
+
+ public void testVisitEndRecord() throws Exception {
+ AnnotationRecorder recorder = new AnnotationRecorder();
+ recorder.visitEnd();
+ recorder.accept(visitor);
+ verify(visitor).visitEnd();
+ }
+
+ public void testVisitEnumRecord() throws Exception {
+ AnnotationRecorder recorder = new AnnotationRecorder();
+ recorder.visitEnum("name", "type-desc", "A");
+ recorder.accept(visitor);
+ verify(visitor).visitEnum("name", "type-desc", "A");
+ }
+
+ public void testVisitAnnotationRecord() throws Exception {
+
+ when(visitor.visitAnnotation("name", "type-desc")).thenReturn(visitor);
+
+ AnnotationRecorder recorder = new AnnotationRecorder();
+ AnnotationVisitor sub = recorder.visitAnnotation("name", "type-desc");
+ sub.visit("name2", "value2");
+ recorder.accept(visitor);
+
+ verify(visitor).visitAnnotation("name", "type-desc");
+ verify(visitor).visit("name2", "value2");
+ }
+
+ public void testVisitArrayRecord() throws Exception {
+
+ when(visitor.visitArray("name")).thenReturn(visitor);
+
+ AnnotationRecorder recorder = new AnnotationRecorder();
+ AnnotationVisitor sub = recorder.visitArray("name");
+ sub.visit("name2", "value2");
+ recorder.accept(visitor);
+
+ verify(visitor).visitArray("name");
+ verify(visitor).visit("name2", "value2");
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistryTestCase.java
new file mode 100644
index 0000000..9ff6a5a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/CompletableBindingRegistryTestCase.java
@@ -0,0 +1,83 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.Type;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 12/07/13
+ * Time: 10:27
+ */
+public class CompletableBindingRegistryTestCase extends TestCase {
+
+ public static final String DESCRIPTOR = "[unknown;";
+
+ @Mock
+ private BindingRegistry delegate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testUnknownDescriptorTriggerCallback() throws Exception {
+ EmptyCompletableBindingRegistry registry = new EmptyCompletableBindingRegistry(delegate);
+ when(delegate.getBindings(DESCRIPTOR)).thenReturn(Collections.<Binding>emptyList());
+
+ registry.getBindings(DESCRIPTOR);
+
+ assertNotNull(registry.type);
+ }
+
+ public void testKnownDescriptorDoNotTriggerCallback() throws Exception {
+ EmptyCompletableBindingRegistry registry = new EmptyCompletableBindingRegistry(delegate);
+ when(delegate.getBindings(DESCRIPTOR)).thenReturn(Collections.<Binding>singletonList(new NullBinding(Type.getType(DESCRIPTOR))));
+
+ registry.getBindings(DESCRIPTOR);
+
+ assertNull(registry.type);
+ }
+
+ private static class EmptyCompletableBindingRegistry extends CompletableBindingRegistry {
+
+ public Type type = null;
+
+ public EmptyCompletableBindingRegistry(final BindingRegistry delegate) {
+ super(delegate, null);
+ }
+
+ @Override
+ protected List<Binding> createBindings(final Type type) {
+ this.type = type;
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistryTestCase.java
new file mode 100644
index 0000000..5495929
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/DefaultBindingRegistryTestCase.java
@@ -0,0 +1,82 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.Type;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/11/12
+ * Time: 10:31 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class DefaultBindingRegistryTestCase extends TestCase {
+
+ public static final Type PROVIDES_TYPE = Type.getType(Provides.class);
+ private BindingRegistry registry;
+
+ @Mock
+ private Reporter reporter;
+ @Mock
+ private AnnotationVisitorFactory factory;
+ @Mock
+ private Predicate predicate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ registry = new DefaultBindingRegistry(reporter);
+ }
+
+ public void testBindingAddition() throws Exception {
+ registry.addBindings(Collections.singletonList(binding()));
+
+ List<Binding> predicates = registry.getBindings(Type.getType(Provides.class).getDescriptor());
+
+ assertEquals(1, predicates.size());
+ Binding found = predicates.get(0);
+ assertNotNull(found);
+ assertEquals(predicate, found.getPredicate());
+ assertEquals(factory, found.getFactory());
+ }
+
+ public void testGetBindingsWhenEmpty() throws Exception {
+ assertTrue(registry.getBindings(PROVIDES_TYPE.getDescriptor()).isEmpty());
+ }
+
+ private Binding binding() {
+ Binding binding = new Binding();
+ binding.setAnnotationType(PROVIDES_TYPE);
+ binding.setFactory(factory);
+ binding.setPredicate(predicate);
+ return binding;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistryTestCase.java
new file mode 100644
index 0000000..d06fda9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/IgnoreAllBindingRegistryTestCase.java
@@ -0,0 +1,58 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 17:36
+ */
+public class IgnoreAllBindingRegistryTestCase extends TestCase {
+ public static final String UNKNOWN_DESCRIPTOR = "[unknown;";
+
+ @Mock
+ private BindingRegistry delegate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testThatNullBindingIsGenerated() throws Exception {
+ when(delegate.getBindings(UNKNOWN_DESCRIPTOR)).thenReturn(Collections.<Binding>emptyList());
+
+ IgnoreAllBindingRegistry registry = new IgnoreAllBindingRegistry(delegate, null);
+
+ List<Binding> bindings = registry.getBindings(UNKNOWN_DESCRIPTOR);
+ assertTrue(bindings.get(0) instanceof NullBinding);
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistryTestCase.java
new file mode 100644
index 0000000..d87ea56
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/LegacyGenericBindingRegistryTestCase.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.manipulator.metadata.annotation.registry;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.Type;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 11/07/13
+ * Time: 17:07
+ */
+public class LegacyGenericBindingRegistryTestCase extends TestCase {
+
+ public static final String AN_IGNORED_ANNOTATION = "[Lan.ignored.Annotation;";
+ public static final String RECOGNISED_IPOJO_ANNOTATION = "[La.recognised.ipojo.Annotation;";
+ public static final String RECOGNISED_HANDLER_ANNOTATION = "[La.recognised.handler.Annotation;";
+
+ @Mock
+ private BindingRegistry delegate;
+
+ @Captor
+ ArgumentCaptor<List<Binding>> capture;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testNonRecognisedTypeAreIgnored() throws Exception {
+ when(delegate.getBindings(AN_IGNORED_ANNOTATION)).thenReturn(Collections.<Binding>emptyList());
+
+ LegacyGenericBindingRegistry registry = new LegacyGenericBindingRegistry(delegate, null);
+
+ List<Binding> bindings = registry.getBindings(AN_IGNORED_ANNOTATION);
+ assertTrue(bindings.isEmpty());
+
+ verify(delegate).addBindings(capture.capture());
+ assertTrue(capture.getValue().isEmpty());
+ }
+
+ public void testIPojoRecognisedTypeAreSupported() throws Exception {
+ when(delegate.getBindings(RECOGNISED_IPOJO_ANNOTATION)).thenReturn(Collections.<Binding>emptyList());
+
+ LegacyGenericBindingRegistry registry = new LegacyGenericBindingRegistry(delegate, null);
+
+ List<Binding> bindings = registry.getBindings(RECOGNISED_IPOJO_ANNOTATION);
+ assertEquals(1, bindings.size());
+
+ verify(delegate).addBindings(capture.capture());
+ Binding one = capture.getValue().get(0);
+ assertEquals(Type.getType(RECOGNISED_IPOJO_ANNOTATION), one.getAnnotationType());
+ }
+
+ public void testHandlerRecognisedTypeAreSupported() throws Exception {
+ when(delegate.getBindings(RECOGNISED_HANDLER_ANNOTATION)).thenReturn(Collections.<Binding>emptyList());
+
+ LegacyGenericBindingRegistry registry = new LegacyGenericBindingRegistry(delegate, null);
+
+ List<Binding> bindings = registry.getBindings(RECOGNISED_HANDLER_ANNOTATION);
+ assertEquals(1, bindings.size());
+
+ verify(delegate).addBindings(capture.capture());
+ Binding one = capture.getValue().get(0);
+ assertEquals(Type.getType(RECOGNISED_HANDLER_ANNOTATION), one.getAnnotationType());
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistryTestCase.java
new file mode 100644
index 0000000..29d82d9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/MetaAnnotationBindingRegistryTestCase.java
@@ -0,0 +1,174 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.HandlerBinding;
+import org.apache.felix.ipojo.annotations.Ignore;
+import org.apache.felix.ipojo.annotations.Stereotype;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.GenericVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.stereotype.StereotypeVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.Type;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 12/07/13
+ * Time: 12:13
+ */
+public class MetaAnnotationBindingRegistryTestCase extends TestCase {
+
+ public static final String DESCRIPTOR = "[Lunknown;";
+ public static final Type TYPE = Type.getType(DESCRIPTOR);
+
+ @Mock
+ private BindingRegistry delegate;
+
+ @Mock
+ private ResourceStore store;
+
+ @Mock
+ private Reporter reporter;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(delegate.getBindings(DESCRIPTOR)).thenReturn(Collections.<Binding>emptyList());
+ }
+
+ public void testAnnotationTypeResourceNotFound() throws Exception {
+ when(store.read(anyString()))
+ .thenThrow(IOException.class);
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ assertTrue(registry.getBindings(DESCRIPTOR).isEmpty());
+ }
+
+ public void testClassicalAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(Classical.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ assertTrue(registry.getBindings(Type.getDescriptor(Classical.class)).isEmpty());
+ }
+
+ public void testStereotypeAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(Stereotyped.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ Binding binding = registry.getBindings(Type.getDescriptor(Stereotyped.class)).get(0);
+ assertTrue(binding.getFactory() instanceof StereotypeVisitorFactory);
+ }
+
+ public void testHandlerBindingAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(Bound.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ Binding binding = registry.getBindings(Type.getDescriptor(Bound.class)).get(0);
+ assertTrue(binding.getFactory() instanceof GenericVisitorFactory);
+ }
+
+ public void testIgnoreAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(Ignored.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ Binding binding = registry.getBindings(Type.getDescriptor(Ignored.class)).get(0);
+ assertTrue(binding instanceof NullBinding);
+ }
+
+ public void testBothStereotypeAndBindingAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(StereotypedBinding.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ List<Binding> bindings = registry.getBindings(Type.getDescriptor(StereotypedBinding.class));
+ assertEquals(2, bindings.size());
+ assertHasVisitorFactories(bindings, StereotypeVisitorFactory.class, GenericVisitorFactory.class);
+ }
+
+ public void testIgnoredWithStereotypeAnnotation() throws Exception {
+ when(store.read(anyString()))
+ .thenReturn(from(StereotypedIgnoredBinding.class));
+ MetaAnnotationBindingRegistry registry = new MetaAnnotationBindingRegistry(delegate, reporter, store);
+ List<Binding> bindings = registry.getBindings(Type.getDescriptor(StereotypedIgnoredBinding.class));
+ assertEquals(1, bindings.size());
+ assertHasVisitorFactories(bindings, NullVisitorFactory.class);
+ }
+
+ private void assertHasVisitorFactories(final List<Binding> bindings,
+ final Class<? extends AnnotationVisitorFactory>... factories) {
+ List<Class<? extends AnnotationVisitorFactory>> existing = new ArrayList<Class<? extends AnnotationVisitorFactory>>();
+ for (Binding binding : bindings) {
+ existing.add(binding.getFactory().getClass());
+ }
+
+ for (Class<? extends AnnotationVisitorFactory> factory : factories) {
+ if (!existing.remove(factory)) {
+ fail("Bindings do not contains expected AnnotationVisitorFactory type: " + factory.getName());
+ }
+ }
+ }
+
+ private byte[] from(Class<?> type) throws IOException {
+ ClassLoader loader = type.getClassLoader();
+ InputStream is = loader.getResourceAsStream(Strings.asResourcePath(type.getName()));
+ return Streams.readBytes(is);
+ }
+
+ private static @interface Classical {}
+
+ @Component
+ @Stereotype
+ private static @interface Stereotyped {}
+
+ @HandlerBinding
+ private static @interface Bound {}
+
+ @Ignore
+ private static @interface Ignored {}
+
+ @Component
+ @Stereotype
+ @HandlerBinding
+ private static @interface StereotypedBinding {}
+
+ @Component
+ @Stereotype
+ @HandlerBinding
+ @Ignore
+ private static @interface StereotypedIgnoredBinding {}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java
new file mode 100644
index 0000000..8ae37f9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java
@@ -0,0 +1,237 @@
+/*
+ * 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.manipulator.metadata.annotation.registry;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.spi.AbsBindingModule;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.hamcrest.Matcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/11/12
+ * Time: 10:49 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class SelectionTestCase extends TestCase {
+ private BindingRegistry registry;
+
+ @Mock
+ private Reporter reporter;
+ @Mock
+ private AnnotationVisitorFactory factory;
+ @Mock
+ private AnnotationVisitor visitor;
+ @Mock
+ private ResourceStore store;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ registry = new DefaultBindingRegistry(reporter);
+ when(factory.newAnnotationVisitor(any(BindingContext.class)))
+ .thenReturn(visitor);
+ // Simulate a resource not found exception
+ when(store.read(anyString()))
+ .thenThrow(new IOException());
+ }
+
+ public void testSelectionOnClassNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnTypeOnly.class);
+ module.load();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnTypeOnly.class, equalTo(visitor));
+ assertFieldSelection(OnTypeOnly.class, nullValue());
+ assertMethodSelection(OnTypeOnly.class, nullValue());
+ assertParameterSelection(OnTypeOnly.class, nullValue());
+ }
+
+ public void testSelectionOnFieldNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnFieldOnly.class);
+ module.load();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnFieldOnly.class, nullValue());
+ assertFieldSelection(OnFieldOnly.class, equalTo(visitor));
+ assertMethodSelection(OnFieldOnly.class, nullValue());
+ assertParameterSelection(OnFieldOnly.class, nullValue());
+
+ }
+
+ public void testSelectionOnMethodNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnMethodOnly.class);
+ module.load();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnMethodOnly.class, nullValue());
+ assertFieldSelection(OnMethodOnly.class, nullValue());
+ assertMethodSelection(OnMethodOnly.class, equalTo(visitor));
+ assertParameterSelection(OnMethodOnly.class, nullValue());
+
+ }
+
+ public void testSelectionOnMethodParameterOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnParameterOnly.class);
+ module.load();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnParameterOnly.class, nullValue());
+ assertFieldSelection(OnParameterOnly.class, nullValue());
+ assertMethodSelection(OnParameterOnly.class, nullValue());
+ assertParameterSelection(OnParameterOnly.class, equalTo(visitor));
+
+ }
+
+ public void testSelectionOBothMethodAndParameter() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnBothMethodAndParameter.class);
+ module.load();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnBothMethodAndParameter.class, nullValue());
+ assertFieldSelection(OnBothMethodAndParameter.class, nullValue());
+ assertMethodSelection(OnBothMethodAndParameter.class, equalTo(visitor));
+ assertParameterSelection(OnBothMethodAndParameter.class, equalTo(visitor));
+
+ }
+
+ private void assertClassSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.type(null, classNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertFieldSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.field(null, fieldNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertMethodSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.method(null, methodNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertParameterSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.parameter(null, methodNode(), 0);
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private MethodNode methodNode() {
+ return new MethodNode(0, "method", "(java/lang/String)V", null, null);
+ }
+
+ private ClassNode classNode() {
+ ClassNode node = new ClassNode();
+ node.visit(0, 0, "my/Component", null, "java/lang/Object", null);
+ return node;
+ }
+
+ public void testSelectionWithEmptyRegistry() throws Exception {
+ Selection selection = new Selection(registry, null, reporter);
+
+ selection.field(null, fieldNode())
+ .annotatedWith(descriptor(OnTypeOnly.class));
+
+ assertNull(selection.get());
+ }
+
+ private String descriptor(Class<? extends Annotation> type) {
+ return Type.getType(type).getDescriptor();
+ }
+
+ private FieldNode fieldNode() {
+ return new FieldNode(0,
+ "field",
+ Type.getType(Object.class).getDescriptor(),
+ null,
+ null);
+ }
+
+ @Target(ElementType.TYPE)
+ private @interface OnTypeOnly {}
+
+ @Target(ElementType.FIELD)
+ private @interface OnFieldOnly {}
+
+ @Target(ElementType.METHOD)
+ private @interface OnMethodOnly {}
+
+ @Target(ElementType.PARAMETER)
+ private @interface OnParameterOnly {}
+
+ @Target({ElementType.PARAMETER, ElementType.METHOD})
+ private @interface OnBothMethodAndParameter {}
+
+
+ private class MonoBindingModule extends AbsBindingModule {
+ private Class<? extends Annotation> type;
+
+ public MonoBindingModule(Class<? extends Annotation> aClass) {
+ this.type = aClass;
+ }
+
+ public void configure() {
+ bind(type).to(factory);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java
new file mode 100644
index 0000000..c3f5914
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.ClassNode;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/10/12
+ * Time: 5:46 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ComponentVisitorTestCase extends TestCase {
+
+ public void testDefaultNameIsClassname() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("my.Component", root.getAttribute("name"));
+ }
+
+ public void testNameAttribute() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("name", "changed");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("changed", root.getAttribute("name"));
+ }
+
+ public void testPublicFactoryDeprecationSupport() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("public_factory", "false");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("false", root.getAttribute("public"));
+ }
+
+ public void testFactoryMethodDeprecationSupport() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("factory_method", "create");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("create", root.getAttribute("factory-method"));
+ }
+
+ private ClassNode clazz() {
+ ClassNode node = new ClassNode();
+ node.name = "my/Component";
+ return node;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitorTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitorTestCase.java
new file mode 100644
index 0000000..1d56258
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitorTestCase.java
@@ -0,0 +1,103 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbenchTestCase.node;
+import static org.mockito.Mockito.mock;
+
+/**
+ * User: guillaume
+ * Date: 14/02/13
+ * Time: 10:22
+ */
+public class HandlerDeclarationVisitorTestCase extends TestCase {
+
+ private Reporter reporter;
+ private ComponentWorkbench workbench;
+ private HandlerDeclarationVisitor visitor;
+
+ @Override
+ public void setUp() throws Exception {
+ reporter = mock(Reporter.class);
+ workbench = new ComponentWorkbench(null, node());
+ workbench.setRoot(new Element("container", null));
+ visitor = new HandlerDeclarationVisitor(workbench, builder(), reporter);
+ }
+
+ public void testElementConversionWithNoNamespace() throws Exception {
+ visitor.visit(null, "<testing/>");
+ visitor.visitEnd();
+
+ Element produced = workbench.build();
+ Element testing = produced.getElements("testing")[0];
+ assertEquals(0, testing.getElements().length);
+ assertEquals(0, testing.getAttributes().length);
+ }
+
+ public void testElementConversionWithNamespace() throws Exception {
+ visitor.visit(null, "<ns:testing xmlns:ns='org.apache.felix.ipojo.testing'/>");
+ visitor.visitEnd();
+
+ Element produced = workbench.build();
+ Element testing = produced.getElements("testing", "org.apache.felix.ipojo.testing")[0];
+ assertEquals(0, testing.getElements().length);
+ assertEquals(0, testing.getAttributes().length);
+ assertNotNull(produced.getElements("org.apache.felix.ipojo.testing:testing"));
+ assertNull(produced.getElements("testing"));
+ }
+
+ public void testAttributeConversionWithNamespace() throws Exception {
+ visitor.visit(null, "<ns:testing xmlns:ns='org.apache.felix.ipojo.testing' ns:name='Guillaume'/>");
+ visitor.visitEnd();
+
+ Element produced = workbench.build();
+ Element testing = produced.getElements("testing", "org.apache.felix.ipojo.testing")[0];
+ assertEquals(0, testing.getElements().length);
+ assertEquals(1, testing.getAttributes().length);
+ assertEquals("Guillaume", testing.getAttribute("name", "org.apache.felix.ipojo.testing"));
+ assertEquals("Guillaume", testing.getAttribute("org.apache.felix.ipojo.testing:name"));
+ }
+
+ public void testAttributeConversionWithNoNamespace() throws Exception {
+ visitor.visit(null, "<ns:testing xmlns:ns='org.apache.felix.ipojo.testing' name='Guillaume'/>");
+ visitor.visitEnd();
+
+ Element produced = workbench.build();
+ Element testing = produced.getElements("testing", "org.apache.felix.ipojo.testing")[0];
+ assertEquals(0, testing.getElements().length);
+ assertEquals(1, testing.getAttributes().length);
+ assertEquals("Guillaume", testing.getAttribute("name"));
+ }
+
+ private DocumentBuilder builder() throws ParserConfigurationException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ return factory.newDocumentBuilder();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitorTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitorTestCase.java
new file mode 100644
index 0000000..b9361bc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitorTestCase.java
@@ -0,0 +1,87 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.bind;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.anyVararg;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 22/05/13
+ * Time: 17:09
+ */
+public class MethodBindVisitorTestCase extends TestCase {
+
+ public void testIdentifierProvided() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, type());
+ MethodNode node = new MethodNode();
+ node.name = "myMethod";
+
+ MethodBindVisitor visitor = new MethodBindVisitor(workbench, Action.BIND, node, reporter);
+ visitor.visit("id", "my-identifier");
+ visitor.visitEnd();
+
+ assertNotNull(workbench.getIds().get("my-identifier"));
+ }
+
+ public void testNoIdentifierButSpecificationAsAttributeProvided() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, type());
+ MethodNode node = new MethodNode();
+ node.name = "notify";
+ node.desc = "()V";
+
+ MethodBindVisitor visitor = new MethodBindVisitor(workbench, Action.BIND, node, reporter);
+ visitor.visit("specification", "my.Service");
+ visitor.visitEnd();
+
+ assertNotNull(workbench.getIds().get("my.Service"));
+ }
+
+ public void testNoIdentifierAndNoSpecificationProvided() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, type());
+ MethodNode node = new MethodNode();
+ node.name = "notify";
+ node.desc = "()V";
+
+ MethodBindVisitor visitor = new MethodBindVisitor(workbench, Action.BIND, node, reporter);
+ visitor.visitEnd();
+
+ verify(reporter).error(anyString(), anyVararg());
+ }
+
+ private static ClassNode type() {
+ ClassNode node = new ClassNode();
+ node.name = "my/Component";
+ return node;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/NamesTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/NamesTestCase.java
new file mode 100644
index 0000000..f1d7035
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/NamesTestCase.java
@@ -0,0 +1,145 @@
+/*
+ * 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.manipulator.metadata.annotation.visitor.util;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.getMethodIdentifier;
+
+import org.objectweb.asm.tree.MethodNode;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 24/05/13
+ * Time: 09:44
+ */
+public class NamesTestCase extends TestCase {
+ public void testComputeEffectiveMethodNameForNotManipulatedMethod() throws Exception {
+ assertEquals("foo", computeEffectiveMethodName("foo"));
+ }
+
+ public void testComputeEffectiveMethodNameForManipulatedMethod() throws Exception {
+ assertEquals("foo", computeEffectiveMethodName("__M_foo"));
+ }
+
+ public void testComputeEffectiveMethodNameForNullInput() throws Exception {
+ assertNull(computeEffectiveMethodName(null));
+ }
+
+ public void testBindPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "bindService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testUnbindPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "unbindService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testSetPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "setService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testUnsetPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "unsetService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testAddPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "addService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testRemovePatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "removeService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testModifiedPatternRecognition() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "modifiedService";
+ assertEquals("Service", getMethodIdentifier(node));
+ }
+
+ public void testNoPatternRecognized() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "notify";
+ node.desc = "()V";
+ assertNull(getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognized() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Lmy/Service;)V";
+ assertEquals("my.Service", getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognizedWithMap() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Lmy/Service;Ljava/util/Map;)V";
+ assertEquals("my.Service", getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognizedWithDictionary() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Lmy/Service;Ljava/util/Dictionary;)V";
+ assertEquals("my.Service", getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognizedWithServiceReference() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Lmy/Service;Lorg/osgi/framework/ServiceReference;)V";
+ assertEquals("my.Service", getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognizedOnlyMap() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Ljava/util/Map;)V";
+ assertNull(getMethodIdentifier(node));
+ }
+
+ public void testSpecificationRecognizedOnlyDictionary() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Ljava/util/Dictionary;)V";
+ assertNull(getMethodIdentifier(node));
+
+ }
+
+ public void testSpecificationRecognizedOnlyServiceReference() throws Exception {
+ MethodNode node = new MethodNode();
+ node.name = "handle";
+ node.desc = "(Lorg/osgi/framework/ServiceReference;)V";
+ assertNull(getMethodIdentifier(node));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java
new file mode 100644
index 0000000..64b446f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.manipulator.render;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.manipulation.ClassManipulator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class ManipulatedMetadataFilterTestCase extends TestCase {
+
+ private ManipulatedMetadataFilter filter;
+
+ @Override
+ public void setUp() throws Exception {
+ filter = new ManipulatedMetadataFilter();
+ }
+
+ public void testFilterPrefixedMethod() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", ClassManipulator.PREFIX + "PropertyName"));
+
+ Assert.assertTrue(filter.accept(main));
+ }
+
+ public void testFilterInstanceManagerValue() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", InstanceManager.class.getName()));
+
+ Assert.assertTrue(filter.accept(main));
+ }
+
+ public void testFilterInstanceManagerSetter() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", "_setInstanceManager"));
+
+ Assert.assertTrue(filter.accept(main));
+ }
+
+ public void testDoNotFilterOthers() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", "setPropertyName"));
+
+ Assert.assertFalse(filter.accept(main));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java
new file mode 100644
index 0000000..e07a1fc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java
@@ -0,0 +1,100 @@
+/*
+ * 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.manipulator.render;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class MetadataRendererTestCase extends TestCase {
+
+ private MetadataRenderer renderer;
+
+ @Override
+ public void setUp() throws Exception {
+ renderer = new MetadataRenderer();
+ }
+
+ public void testAddMetadataFilter() throws Exception {
+
+ // Auto remove all elements with a namespace
+ renderer.addMetadataFilter(new MetadataFilter() {
+ public boolean accept(Element element) {
+ return element.getNameSpace() != null;
+ }
+ });
+
+ Element main = new Element("test", null);
+ Element child = new Element("child", "uri");
+ main.addElement(child);
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { }", rendered);
+
+ }
+
+ public void testRenderElementWithNoNamespace() throws Exception {
+ Element main = new Element("test", null);
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { }", rendered);
+ }
+
+ public void testRenderElementWithEmptyNamespace() throws Exception {
+ Element main = new Element("test", "");
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { }", rendered);
+ }
+
+ public void testRenderElementWithDefaultNamespace() throws Exception {
+ // TODO Do we need to strip off default namespace ?
+ Element main = new Element("test", "org.apache.felix.ipojo");
+ String rendered = renderer.render(main);
+ Assert.assertEquals("org.apache.felix.ipojo:test { }", rendered);
+ }
+
+ public void testRenderElementWithNamespace() throws Exception {
+ Element main = new Element("test", "http://felix.apache.org/ipojo/testing");
+ String rendered = renderer.render(main);
+ Assert.assertEquals("http://felix.apache.org/ipojo/testing:test { }", rendered);
+ }
+
+ public void testRenderElementWithNoNamespaceAttribute() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", "attribute"));
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { $name=\"attribute\" }", rendered);
+ }
+
+ public void testRenderElementWithNamespaceAttribute() throws Exception {
+ Element main = new Element("test", null);
+ main.addAttribute(new Attribute("name", "ns-uri", "attribute"));
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { $ns-uri:name=\"attribute\" }", rendered);
+ }
+
+ public void testRenderElementWithChildren() throws Exception {
+ Element main = new Element("test", null);
+ Element child = new Element("child", null);
+ main.addElement(child);
+ String rendered = renderer.render(main);
+ Assert.assertEquals("test { child { }}", rendered);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java
new file mode 100644
index 0000000..3374522
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java
@@ -0,0 +1,259 @@
+/*
+ * 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.manipulator.spi;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.GenericVisitorFactory;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ignore.NullBinding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.stereotype.StereotypeVisitorFactory;
+
+import java.lang.annotation.ElementType;
+import java.util.Iterator;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+import static org.mockito.Mockito.mock;
+import static org.objectweb.asm.Type.getType;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/10/12
+ * Time: 10:37 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class AbsBindingModuleTestCase extends TestCase {
+
+ public void testSimpleBinding() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Provides.class), one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Only 1 Binding
+ assertFalse(i.hasNext());
+ }
+
+ public void testTwoBindings() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ bind(Requires.class).to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Provides.class), one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(getType(Requires.class), two.getAnnotationType());
+ assertEquals(factory, two.getFactory());
+ }
+
+ public void testTwoBindingsForSameAnnotation() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ final AnnotationVisitorFactory factory2 = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ bind(Provides.class).to(factory2);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Provides.class), one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(getType(Provides.class), two.getAnnotationType());
+ assertEquals(factory2, two.getFactory());
+ }
+
+ public void testConditionalBinding() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class)
+ .when(on(ElementType.FIELD))
+ .to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Provides.class), one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Only 1 Binding
+ assertFalse(i.hasNext());
+ }
+
+ public void testConditionalBindings() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ final AnnotationVisitorFactory factory2 = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class)
+ .when(on(ElementType.FIELD))
+ .to(factory)
+ .when(on(ElementType.PARAMETER))
+ .to(factory2);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Provides.class), one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(getType(Provides.class), two.getAnnotationType());
+ assertEquals(factory2, two.getFactory());
+ }
+
+ public void testHandlerBindings() throws Exception {
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bindHandlerBinding(Bound.class).to("com.acme", "foo");
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Bound.class), one.getAnnotationType());
+ assertTrue(one.getFactory() instanceof GenericVisitorFactory);
+ }
+
+ public void testStereotypeBindings() throws Exception {
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bindStereotype(Bound.class)
+ .with(new ComponentLiteral() {
+ @Override
+ public boolean publicFactory() {
+ return false;
+ }
+ });
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(getType(Bound.class), one.getAnnotationType());
+ assertTrue(one.getFactory() instanceof StereotypeVisitorFactory);
+ }
+
+
+ public void testIgnoreBindings() throws Exception {
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bindIgnore(Bound.class);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertEquals(getType(Bound.class), one.getAnnotationType());
+ assertTrue(one instanceof NullBinding);
+ }
+
+ private static @interface Bound {}
+
+ private static class ComponentLiteral extends AnnotationLiteral<Component> implements Component {
+
+ public boolean public_factory() {
+ return true;
+ }
+
+ public boolean publicFactory() {
+ return true;
+ }
+
+ public String name() {
+ return "";
+ }
+
+ public boolean architecture() {
+ return false;
+ }
+
+ public boolean immediate() {
+ return false;
+ }
+
+ public boolean propagation() {
+ return false;
+ }
+
+ public String managedservice() {
+ return "";
+ }
+
+ public String factory_method() {
+ return "";
+ }
+
+ public String factoryMethod() {
+ return "";
+ }
+
+ public String version() {
+ return "";
+ }
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteralTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteralTestCase.java
new file mode 100644
index 0000000..54f2ab8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AnnotationLiteralTestCase.java
@@ -0,0 +1,50 @@
+/*
+ * 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.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.spi.AnnotationLiteral;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 28/06/13
+ * Time: 14:40
+ */
+public class AnnotationLiteralTestCase extends TestCase {
+ public void testAnnotationTypeDiscovery() throws Exception {
+
+ FooLiteral fooLiteral = new FooLiteral() {
+ public String value() {
+ return "a";
+ }
+ };
+
+ assertEquals(Foo.class, fooLiteral.annotationType());
+ assertEquals("a", fooLiteral.value());
+
+ }
+
+ private static abstract class FooLiteral extends AnnotationLiteral<Foo> implements Foo { }
+
+ private static @interface Foo {
+ String value();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java
new file mode 100644
index 0000000..2494ba8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java
@@ -0,0 +1,88 @@
+/*
+ * 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.manipulator.store;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * A {@code DirectoryBytecodeStoreTestCase} is ...
+ *
+ */
+public class DirectoryResourceStoreTestCase extends TestCase {
+
+ private DirectoryResourceStore store;
+ private File classes;
+ private File out;
+
+ public void setUp() throws Exception {
+ classes = new File("target", "classes");
+ out = new File(classes, "test.txt");
+ store = new DirectoryResourceStore(classes);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ out.delete();
+ }
+
+ public void testAccessibleResources() throws Exception {
+ byte[] data = store.read(Streams.class.getName().replace('.', '/').concat(".class"));
+ assertNotNull("Data cannot be null", data);
+ }
+
+ public void testInaccessibleResources() throws Exception {
+ try {
+ store.read("something/that/do/not/exists.txt");
+ fail();
+ } catch (IOException ioe) {
+ // Expected
+ }
+ }
+
+ public void testResourceWriting() throws Exception {
+ store.write("test.txt", "Hello World".getBytes());
+ Assert.assertTrue(out.isFile());
+ }
+
+ public void testResourceVisitor() throws Exception {
+
+ // final String expectedPath = Strings.asResourcePath(Pojoization.class.getName());
+ ResourceVisitor visitor = mock(ResourceVisitor.class);
+ store.accept(visitor);
+
+ verify(visitor, atLeastOnce()).visit(anyString());
+
+ // TODO try to check that Pojoization class resource was called
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java
new file mode 100644
index 0000000..ef07dbf
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java
@@ -0,0 +1,82 @@
+/*
+ * 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.manipulator.store;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+
+import java.io.File;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class JarFileResourceStoreTestCase extends TestCase {
+ public static final String RESOURCE_PATH = "org/apache/felix/ipojo/test/scenarios/component/Annotation.class";
+ private JarFileResourceStore store;
+ private File out;
+
+ public void setUp() throws Exception {
+ File classes = new File("target", "test-classes");
+ out = new File(classes, "test-store.jar");
+ JarFile jar = new JarFile(new File(classes, "tests.manipulation.java5.jar"));
+ store = new JarFileResourceStore(jar, out);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ out.delete();
+ }
+
+ public void testRead() throws Exception {
+ byte[] bytes = store.read(RESOURCE_PATH);
+ Assert.assertNotNull(bytes);
+ }
+
+ public void testAccept() throws Exception {
+ ResourceVisitor visitor = mock(ResourceVisitor.class);
+ store.accept(visitor);
+
+ verify(visitor, atLeastOnce()).visit(anyString());
+
+ }
+
+ public void testWrite() throws Exception {
+
+ ManifestBuilder builder = mock(ManifestBuilder.class);
+ Manifest manifest = new Manifest();
+ when(builder.build(any(Manifest.class))).thenReturn(manifest);
+ store.setManifestBuilder(builder);
+
+ store.write(RESOURCE_PATH, "Hello World".getBytes());
+
+ store.close();
+
+ JarFile outJar = new JarFile(out);
+ Assert.assertNotNull(outJar.getEntry(RESOURCE_PATH));
+ byte[] bytes = Streams.readBytes(outJar.getInputStream(outJar.getEntry(RESOURCE_PATH)));
+
+ Assert.assertEquals("Hello World", new String(bytes));
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java
new file mode 100644
index 0000000..ce551e0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java
@@ -0,0 +1,99 @@
+/*
+ * 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.manipulator.store.builder;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.store.ManifestBuilder;
+import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder;
+import org.apache.felix.ipojo.manipulator.util.Constants;
+
+public class DefaultManifestBuilderTestCase extends TestCase {
+
+ private static final String ORG_OSGI_FRAMEWORK_VERSION_1_5 = "org.osgi.framework;version=1.5";
+ private Manifest manifest;
+ private ManifestBuilder builder;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.putValue("Import-Package", ORG_OSGI_FRAMEWORK_VERSION_1_5);
+ attributes.putValue("Created-By", "TestCase");
+
+ builder = new DefaultManifestBuilder();
+ builder.addReferredPackage(Collections.singleton("org.osgi.service.http"));
+ }
+
+ public void testManifestIsModified() throws Exception {
+ Manifest modified = builder.build(manifest);
+
+ // Created by header was properly modified
+ Assert.assertEquals("TestCase & iPOJO " + Constants.getVersion(),
+ modified.getMainAttributes().getValue("Created-By"));
+
+ // As there was no metadata provided, no iPOJO-Components header should be present
+ Assert.assertNull(modified.getMainAttributes().getValue("iPOJO-Components"));
+
+ // Check that default manipulation introduced packages are present
+ String imported = modified.getMainAttributes().getValue("Import-Package");
+ Assert.assertTrue(imported.contains(ORG_OSGI_FRAMEWORK_VERSION_1_5));
+ Assert.assertTrue(imported.contains("org.apache.felix.ipojo"));
+ Assert.assertTrue(imported.contains("org.apache.felix.ipojo.architecture"));
+ Assert.assertTrue(imported.contains("org.osgi.service.cm"));
+ Assert.assertTrue(imported.contains("org.osgi.service.log"));
+ }
+
+
+ public void testCreatedByHeaderDoesNotContainIPojoTwice() throws Exception {
+
+ manifest.getMainAttributes().putValue("Created-By", "TestCase for iPOJO");
+
+ Manifest modified = builder.build(manifest);
+
+ // Created by header was properly not changed
+ Assert.assertEquals("TestCase for iPOJO",
+ modified.getMainAttributes().getValue("Created-By"));
+ }
+
+ public void testReferredPackagesAreProperlyAdded() throws Exception {
+
+ List<String> p = Arrays.asList("org.apache.felix.ipojo.test", "org.apache.felix.ipojo.log");
+ builder.addReferredPackage(new HashSet<String>(p));
+
+ Manifest modified = builder.build(manifest);
+
+ // Check that referred packages are present
+ String imported = modified.getMainAttributes().getValue("Import-Package");
+ Assert.assertTrue(imported.contains("org.apache.felix.ipojo.test"));
+ Assert.assertTrue(imported.contains("org.apache.felix.ipojo.log"));
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java
new file mode 100644
index 0000000..c7e6175
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java
@@ -0,0 +1,75 @@
+/*
+ * 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.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class FileSystemResourceMapperTestCase extends TestCase {
+
+ public void testUnixInternalize() throws Exception {
+
+ ResourceMapper delegate = mock(ResourceMapper.class);
+ FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+ String path = "this/is/a/unix/like/path.extension";
+ when(delegate.internalize(eq(path))).thenReturn(path);
+
+ String result = mapper.internalize(path);
+
+ Assert.assertEquals(path, result);
+
+ }
+
+ public void testUnixExternalize() throws Exception {
+
+ ResourceMapper delegate = mock(ResourceMapper.class);
+ FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+ String path = "this/is/a/unix/like/path.extension";
+ when(delegate.externalize(eq(path))).thenReturn(path);
+
+ String result = mapper.externalize(path);
+
+ // unix path is already normalized
+ Assert.assertEquals(path, result);
+ }
+
+ public void ignoreWindowsExternalize() throws Exception {
+ // As Java doesn't like '\' alone in Strings I have to replace them on the fly :'(
+ // Grrr doesn't work as expected
+ ResourceMapper delegate = mock(ResourceMapper.class);
+ FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+ String path = "c:\\this\\is\\a\\windows\\like\\path.extension";
+ when(delegate.externalize(eq(path))).thenReturn(path);
+
+ String expected = "c:/this/is/a/windows/like/path.extension";
+ String result = mapper.externalize(path);
+
+ // unix path is already normalized
+ Assert.assertEquals(expected, result);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java
new file mode 100644
index 0000000..cfde446
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java
@@ -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.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class IdentityResourceMapperTestCase extends TestCase {
+ public void testInternalize() throws Exception {
+ IdentityResourceMapper mapper = new IdentityResourceMapper();
+ String path = "must/not/change";
+ Assert.assertEquals(path, mapper.internalize(path));
+ }
+
+ public void testExternalize() throws Exception {
+ IdentityResourceMapper mapper = new IdentityResourceMapper();
+ String path = "must/not/change";
+ Assert.assertEquals(path, mapper.externalize(path));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java
new file mode 100644
index 0000000..bb6f75c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+public class WABResourceMapperTestCase extends TestCase {
+
+ public void testWebInfClassesResourceIsMapped() throws Exception {
+ ResourceMapper mapper = new WABResourceMapper();
+
+ String normalized = "jndi.properties";
+ String resource = "WEB-INF/classes/jndi.properties";
+
+ Assert.assertEquals(normalized, mapper.externalize(resource));
+ Assert.assertEquals(resource, mapper.internalize(normalized));
+ }
+
+ public void testWebInfLibResourceIsUnchanged() throws Exception {
+ ResourceMapper mapper = new WABResourceMapper();
+
+ String normalized = "WEB-INF/lib/commons-logging.jar";
+ String resource = "WEB-INF/lib/commons-logging.jar";
+
+ Assert.assertEquals(normalized, mapper.externalize(resource));
+ Assert.assertEquals(resource, mapper.internalize(normalized));
+ }
+
+ public void testMetaInfManifestIsUnchanged() throws Exception {
+ ResourceMapper mapper = new WABResourceMapper();
+
+ String normalized = "META-INF/MANIFEST.MF";
+ String resource = "META-INF/MANIFEST.MF";
+
+ Assert.assertEquals(normalized, mapper.externalize(resource));
+ Assert.assertEquals(resource, mapper.internalize(normalized));
+ }
+
+ public void testResourceNotMapped() throws Exception {
+ ResourceMapper mapper = new WABResourceMapper();
+
+ String resource = "images/logo.png";
+
+ Assert.assertEquals(resource, mapper.internalize(resource));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java
new file mode 100644
index 0000000..2dcf26d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java
@@ -0,0 +1,59 @@
+/*
+ * 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.manipulator.util;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class StreamsTestCase extends TestCase {
+ public void testSimpleClose() throws Exception {
+ Closeable closeable = mock(Closeable.class);
+ Streams.close(closeable);
+ verify(closeable).close();
+ }
+
+ public void testCloseWithNullParameter() throws Exception {
+ Closeable closeable = mock(Closeable.class);
+ Streams.close(closeable, null);
+ verify(closeable).close();
+ }
+
+ public void testTransfer() throws Exception {
+ String toBeRead = "Tadam";
+ ByteArrayInputStream bais = new ByteArrayInputStream(toBeRead.getBytes());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Streams.transfer(bais, baos);
+ Assert.assertEquals(toBeRead, new String(baos.toByteArray()));
+ }
+
+ public void testReadBytes() throws Exception {
+ String toBeRead = "Tadam";
+ ByteArrayInputStream bais = new ByteArrayInputStream(toBeRead.getBytes());
+ byte[] bytes = Streams.readBytes(bais);
+ Assert.assertEquals(toBeRead, new String(bytes));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java
new file mode 100644
index 0000000..1ccb075
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java
@@ -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.manipulator.util;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class StringsTestCase extends TestCase {
+
+ private static final String CLASSNAME = StringsTestCase.class.getName();
+ private static final String PATH = "org/apache/felix/ipojo/manipulator/util/StringsTestCase.class";
+
+ public void testClassnameIsTransformedIntoNormalizedResourcePath() throws Exception {
+ Assert.assertEquals(PATH, Strings.asResourcePath(CLASSNAME));
+ }
+
+ public void testNormalizedResourcePathIsTransformedIntoClassname() throws Exception {
+ Assert.assertEquals(CLASSNAME, Strings.asClassName(PATH));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java
new file mode 100644
index 0000000..72e45a0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * 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.manipulator.visitor.check;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.*;
+
+
+public class CheckFieldConsistencyResultVisitorTestCase extends TestCase {
+
+ @Mock
+ private Reporter reporter;
+
+ @Mock
+ private ManipulationResultVisitor delegate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testVisitClassStructureOK() throws Exception {
+ Element component = newComponentElement();
+ CheckFieldConsistencyResultVisitor visitor = new CheckFieldConsistencyResultVisitor(delegate);
+ visitor.setReporter(reporter);
+ visitor.setMetadata(component);
+
+ Element manipulation = newManipulationElement(true);
+ visitor.visitClassStructure(manipulation);
+
+ verifyZeroInteractions(reporter);
+
+ }
+
+ public void testVisitClassStructureWithMissingFields() throws Exception {
+ Element component = newComponentElement();
+ CheckFieldConsistencyResultVisitor visitor = new CheckFieldConsistencyResultVisitor(delegate);
+ visitor.setReporter(reporter);
+ visitor.setMetadata(component);
+
+ Element manipulation = newManipulationElement(false);
+ visitor.visitClassStructure(manipulation);
+
+ verify(reporter).error(anyString());
+
+ }
+
+ private Element newManipulationElement(boolean complete) {
+ Element manipulation = new Element("manipulation", null);
+ if (complete) {
+ Element field = new Element("field", null);
+ field.addAttribute(new Attribute("name", "property"));
+ manipulation.addElement(field);
+ }
+
+ return manipulation;
+ }
+
+ private Element newComponentElement() {
+ Element component = new Element("component", null);
+ Element requires = new Element("requires", null);
+ requires.addAttribute(new Attribute("field", "property"));
+ component.addElement(requires);
+
+ return component;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java
new file mode 100644
index 0000000..346032f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java
@@ -0,0 +1,64 @@
+/*
+ * 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.manipulator.visitor.writer;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.*;
+
+
+public class ManipulatedResourcesWriterTestCase extends TestCase {
+
+ @Mock
+ private Reporter reporter;
+
+ @Mock
+ private ResourceStore store;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testVisitManipulationResult() throws Exception {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(reporter);
+ writer.setResourceStore(store);
+
+ Element component = new Element("component", null);
+ assertNotNull(writer.visitManipulationResult(component));
+ verify(store).writeMetadata(same(component));
+ }
+
+ public void testVisitMetadata() throws Exception {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(reporter);
+ writer.setResourceStore(store);
+
+ Element instance = new Element("instance", null);
+ writer.visitMetadata(instance);
+ verify(store).writeMetadata(same(instance));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java
new file mode 100644
index 0000000..3a5f5d3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java
@@ -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.felix.ipojo.manipulator.visitor.writer;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import static org.mockito.Mockito.*;
+
+
+public class ManipulatedResultWriterTestCase extends TestCase {
+
+ @Spy
+ private Element element = new Element("component", null);
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testVisitClassStructure() throws Exception {
+ ManipulatedResultWriter writer = new ManipulatedResultWriter(element);
+
+ Element manipulation = new Element("manipulation", null);
+ writer.visitClassStructure(manipulation);
+ verify(element).addElement(same(manipulation));
+ }
+
+ public void testVisitManipulatedResource() throws Exception {
+ ManipulatedResultWriter writer = new ManipulatedResultWriter(element);
+
+ writer.visitManipulatedResource("test.class", "Hello".getBytes());
+
+ assertNotNull(writer.getResources().get("test.class"));
+ assertEquals("Hello", new String(writer.getResources().get("test.class")));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java b/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java
new file mode 100644
index 0000000..9b58797
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java
@@ -0,0 +1,39 @@
+/*
+ * 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 test;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.framework.BundleContext;
+
+@Component
+public class AnnotatedComponent {
+
+ @Property
+ private String prop;
+
+ public AnnotatedComponent(BundleContext bundleContext) {}
+
+ @FakeAnnotation
+ public void annotatedMethod() {
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/Child.java b/ipojo/manipulator/manipulator/src/test/java/test/Child.java
new file mode 100644
index 0000000..2523415
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/Child.java
@@ -0,0 +1,36 @@
+/*
+ * 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 test;
+
+public class Child extends Parent {
+
+ Child(int i, String f) {
+ super(i, f);
+ }
+
+ Child() {
+ super(5, "foo");
+ }
+
+ public int doSomething() {
+ return getIndex() + 1; // 9
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java b/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java
new file mode 100755
index 0000000..5948868
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java
@@ -0,0 +1,41 @@
+/*
+ * 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 test;
+
+import java.util.ArrayList;
+
+public class ClusterDaemon {
+
+
+ /**
+ * Controled servers url list.
+ */
+ private ArrayList ControlledServersNames;
+
+ /**
+ * Controlled servers.
+ * @return cluster daemon controlled server names.
+ */
+ public ArrayList getControlledServersNames() {
+ return null;
+ }
+
+
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java b/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java
new file mode 100644
index 0000000..585788b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java
@@ -0,0 +1,31 @@
+/*
+ * 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 test;
+
+
+public class ConstructorCheck {
+
+ public String m_foo;
+
+ public ConstructorCheck(String foo) {
+ m_foo = foo;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/DoubleArray.java b/ipojo/manipulator/manipulator/src/test/java/test/DoubleArray.java
new file mode 100644
index 0000000..f20c7e5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/DoubleArray.java
@@ -0,0 +1,44 @@
+/*
+ * 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 test;
+
+/**
+ * Checks a component with a double array
+ * To reproduce https://issues.apache.org/jira/browse/FELIX-3621
+ */
+public class DoubleArray {
+
+ public boolean start() {
+ System.out.println("Start");
+
+ int[][] matrix = new int[20][20];
+
+ this.testArray(matrix);
+
+ matrix[0][0] = 2;
+ return true;
+ }
+
+ private void testArray(int[][] matrix) {
+ System.out.println("Test Array");
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java b/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java
new file mode 100644
index 0000000..21d2076
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/FakeAnnotation.java
@@ -0,0 +1,35 @@
+/*
+ * 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 test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A {@code FakeAnnotation} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FakeAnnotation {
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java b/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java
new file mode 100644
index 0000000..b9d7a02
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java
@@ -0,0 +1,34 @@
+/*
+ * 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 test;
+
+public class NoValidConstructor {
+
+ String m_s;
+
+ public NoValidConstructor(String s) {
+ m_s = s;
+ }
+
+ public String getS() {
+ return m_s;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/NonSunClass.java b/ipojo/manipulator/manipulator/src/test/java/test/NonSunClass.java
new file mode 100644
index 0000000..1df0e50
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/NonSunClass.java
@@ -0,0 +1,38 @@
+/*
+ * 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 test;
+
+/**
+ * Class that does not respect Sun conventions.
+ */
+public class NonSunClass {
+
+ /**
+ * Does not match the Sun convention.
+ */
+ private boolean S1 = true;
+
+ public boolean getS1() {
+ return S1;
+ }
+
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/Parent.java b/ipojo/manipulator/manipulator/src/test/java/test/Parent.java
new file mode 100644
index 0000000..4f4954c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/Parent.java
@@ -0,0 +1,34 @@
+/*
+ * 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 test;
+
+public class Parent {
+
+ private int m_index = 0;
+
+ public Parent(int i, String s) {
+ m_index = i + s.length();
+ }
+
+ public int getIndex() {
+ return m_index;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/PlentyOfAnnotations.java b/ipojo/manipulator/manipulator/src/test/java/test/PlentyOfAnnotations.java
new file mode 100644
index 0000000..b6d11ed
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/PlentyOfAnnotations.java
@@ -0,0 +1,63 @@
+/*
+ * 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 test;
+
+import org.apache.felix.ipojo.annotations.*;
+import test.ipojo.ExternalHandler;
+
+import java.util.List;
+
+@Component
+@Instantiate
+public class PlentyOfAnnotations {
+
+ @Requires
+ List list;
+ private String m_prop;
+ private Runnable m_runnable;
+ private String m_stuff;
+
+ @ExternalHandler
+ private String stuff2;
+
+
+ PlentyOfAnnotations(@Property String prop, @Requires Runnable runnable, @ExternalHandler String stuff) {
+
+ m_prop = prop;
+ m_runnable = runnable;
+ m_stuff = stuff;
+
+ }
+
+ @Validate
+ public void start() {
+ //...
+ }
+
+ @ExternalHandler
+ public void stuff() {
+ // ...
+ }
+
+ public String doSomethingWithArguments(String message, int value) {
+ return message + " - " + value;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java b/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java
new file mode 100644
index 0000000..7b12a90
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java
@@ -0,0 +1,40 @@
+/*
+ * 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 test;
+
+public class PojoWithInner {
+
+ private MyInner m_result = new MyInner();
+
+ // This is a simple POJO
+
+ public boolean doSomething() {
+ return m_result.getInner();
+ }
+
+ public class MyInner {
+
+ public boolean getInner() {
+ return true;
+ }
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java b/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java
new file mode 100644
index 0000000..fb8a8da
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java
@@ -0,0 +1,32 @@
+/*
+ * 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 test;
+
+public class SimplePojo {
+
+ private boolean m_result = true;
+
+ // This is a simple POJO
+
+ public boolean doSomething() {
+ return m_result;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/frames/CryptoServiceSingleton.java b/ipojo/manipulator/manipulator/src/test/java/test/frames/CryptoServiceSingleton.java
new file mode 100644
index 0000000..62823fa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/frames/CryptoServiceSingleton.java
@@ -0,0 +1,434 @@
+/*
+ * #%L
+ * Wisdom-Framework
+ * %%
+ * Copyright (C) 2013 - 2014 Wisdom Framework
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package test.frames;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+
+import javax.crypto.*;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+/**
+ * This component triggers some interesting frames issue.
+ */
+@Component
+@Provides
+@Instantiate(name = "crypto")
+public class CryptoServiceSingleton {
+
+ public static final String AES_CBC_ALGORITHM = "AES/CBC/PKCS5Padding";
+ public static final String AES_ECB_ALGORITHM = "AES";
+ private static final Charset UTF_8 = Charset.defaultCharset();
+ public static final String HMAC_SHA_1 = "HmacSHA1";
+ public static final String PBKDF_2_WITH_HMAC_SHA_1 = "PBKDF2WithHmacSHA1";
+
+ private int keySize;
+ private int iterationCount;
+ private Hash defaultHash;
+
+ private final String secret;
+
+ public CryptoServiceSingleton(String secret, Hash defaultHash,
+ Integer keySize, Integer iterationCount) {
+ this.secret = secret;
+ this.defaultHash = defaultHash;
+ this.keySize = keySize;
+ this.iterationCount = iterationCount;
+ }
+
+ public CryptoServiceSingleton() {
+ this(
+ "I;>qOs/VgFe?l@>Kn/RGa0p9b1ji?Kg7uhjAPHdIO8>@<em_AFs[BAMUQ0D]eOLV",
+ Hash.valueOf("MD5"),
+ 128,
+ 20);
+ }
+
+
+ /**
+ * Generate the AES key from the salt and the private key.
+ *
+ * @param salt the salt (hexadecimal)
+ * @param privateKey the private key
+ * @return the generated key.
+ */
+ private SecretKey generateAESKey(String privateKey, String salt) {
+ try {
+ byte[] raw = Hex.decodeHex(salt.toCharArray());
+ KeySpec spec = new PBEKeySpec(privateKey.toCharArray(), raw, iterationCount, keySize);
+ SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_1);
+ return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), AES_ECB_ALGORITHM);
+ } catch (DecoderException e) {
+ throw new IllegalStateException(e);
+ } catch ( NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e);
+ } catch (InvalidKeySpecException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Encrypt a String with the AES encryption advanced using 'AES/CBC/PKCS5Padding'. Unlike the regular
+ * encode/decode AES method using ECB (Electronic Codebook), it uses Cipher-block chaining (CBC). The salt must be
+ * valid hexadecimal String. This method uses parts of the application secret as private key and initialization
+ * vector.
+ *
+ * @param value The message to encrypt
+ * @param salt The salt (hexadecimal String)
+ * @return encrypted String encoded using Base64
+ */
+ public String encryptAESWithCBC(String value, String salt) {
+ return encryptAESWithCBC(value, getSecretPrefix(), salt, getDefaultIV());
+ }
+
+ /**
+ * Encrypt a String with the AES encryption advanced using 'AES/CBC/PKCS5Padding'. Unlike the regular
+ * encode/decode AES method using ECB (Electronic Codebook), it uses Cipher-block chaining (CBC). The private key
+ * must have a length of 16 bytes, the salt and initialization vector must be valid hex Strings.
+ *
+ * @param value The message to encrypt
+ * @param privateKey The private key
+ * @param salt The salt (hexadecimal String)
+ * @param iv The initialization vector (hexadecimal String)
+ * @return encrypted String encoded using Base64
+ */
+ public String encryptAESWithCBC(String value, String privateKey, String salt, String iv) {
+ SecretKey genKey = generateAESKey(privateKey, salt);
+ byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, genKey, iv, value.getBytes(UTF_8));
+ return new String(Base64.encodeBase64(encrypted), UTF_8);
+ }
+
+ /**
+ * Decrypt a String with the AES encryption advanced using 'AES/CBC/PKCS5Padding'. Unlike the regular
+ * encode/decode AES method using ECB (Electronic Codebook), it uses Cipher-block chaining (CBC). The salt and
+ * initialization vector must be valid hex Strings. This method use parts of the application secret as private
+ * key and the default initialization vector.
+ *
+ * @param value An encrypted String encoded using Base64.
+ * @param salt The salt (hexadecimal String)
+ * @return The decrypted String
+ */
+ public String decryptAESWithCBC(String value, String salt) {
+ return decryptAESWithCBC(value, getSecretPrefix(), salt, getDefaultIV());
+ }
+
+ /**
+ * Decrypt a String with the AES encryption advanced using 'AES/CBC/PKCS5Padding'. Unlike the regular
+ * encode/decode AES method using ECB (Electronic Codebook), it uses Cipher-block chaining (CBC). The private key
+ * must have a length of 16 bytes, the salt and initialization vector must be valid hexadecimal Strings.
+ *
+ * @param value An encrypted String encoded using Base64.
+ * @param privateKey The private key
+ * @param salt The salt (hexadecimal String)
+ * @param iv The initialization vector (hexadecimal String)
+ * @return The decrypted String
+ */
+ public String decryptAESWithCBC(String value, String privateKey, String salt, String iv) {
+ SecretKey key = generateAESKey(privateKey, salt);
+ byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, decodeBase64(value));
+ return new String(decrypted, UTF_8);
+ }
+
+ /**
+ * Utility method encrypting/decrypting the given message.
+ * The sense of the operation is specified using the `encryptMode` parameter.
+ *
+ * @param encryptMode encrypt or decrypt mode ({@link javax.crypto.Cipher#DECRYPT_MODE} or
+ * {@link javax.crypto.Cipher#ENCRYPT_MODE}).
+ * @param generatedKey the generated key
+ * @param vector the initialization vector
+ * @param message the plain/cipher text to encrypt/decrypt
+ * @return the encrypted or decrypted message
+ */
+ private byte[] doFinal(int encryptMode, SecretKey generatedKey, String vector, byte[] message) {
+ try {
+ byte[] raw = Hex.decodeHex(vector.toCharArray());
+ Cipher cipher = Cipher.getInstance(AES_CBC_ALGORITHM);
+ cipher.init(encryptMode, generatedKey, new IvParameterSpec(raw));
+ return cipher.doFinal(message);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Sign a message using the application secret key (HMAC-SHA1).
+ */
+ public String sign(String message) {
+ return sign(message, secret.getBytes(UTF_8));
+ }
+
+ /**
+ * Sign a message with a key.
+ *
+ * @param message The message to sign
+ * @param key The key to use
+ * @return The signed message (in hexadecimal)
+ */
+ public String sign(String message, byte[] key) {
+ try {
+ // Get an hmac_sha1 key from the raw key bytes
+ SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA_1);
+
+ // Get an hmac_sha1 Mac instance and initialize with the signing key
+ Mac mac = Mac.getInstance(HMAC_SHA_1);
+ mac.init(signingKey);
+
+ // Compute the hmac on input data bytes
+ byte[] rawHmac = mac.doFinal(message.getBytes(UTF_8));
+
+ // Convert raw bytes to Hex
+ byte[] hexBytes = new Hex().encode(rawHmac);
+
+ // Covert array of Hex bytes to a String
+ return new String(hexBytes, UTF_8);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Create a hash using the default hashing algorithm.
+ *
+ * @param input The password
+ * @return The password hash
+ */
+ public String hash(String input) {
+ return hash(input, defaultHash);
+ }
+
+ /**
+ * Create a hash using specific hashing algorithm.
+ *
+ * @param input The password
+ * @param hashType The hashing algorithm
+ * @return The password hash
+ */
+ public String hash(String input, Hash hashType) {
+ try {
+ MessageDigest m = MessageDigest.getInstance(hashType.toString());
+ byte[] out = m.digest(input.getBytes(UTF_8));
+ return new String(Base64.encodeBase64(out), UTF_8);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Encrypt a String with the AES standard encryption (using the ECB mode) using the default secret (the
+ * application secret).
+ *
+ * @param value The String to encrypt
+ * @return An hexadecimal encrypted string
+ */
+ public String encryptAES(String value) {
+ return encryptAES(value, getSecretPrefix());
+ }
+
+ /**
+ * Encrypt a String with the AES standard encryption (using the ECB mode). Private key must have a length of 16 bytes.
+ *
+ * @param value The String to encrypt
+ * @param privateKey The key used to encrypt
+ * @return An hexadecimal encrypted string
+ */
+ public String encryptAES(String value, String privateKey) {
+ try {
+ byte[] raw = privateKey.getBytes(UTF_8);
+ SecretKeySpec skeySpec = new SecretKeySpec(raw, AES_ECB_ALGORITHM);
+ Cipher cipher = Cipher.getInstance(AES_ECB_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+ return Hex.encodeHexString(cipher.doFinal(value.getBytes(UTF_8)));
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Decrypt a String with the standard AES encryption (using the ECB mode) using the default secret (the
+ * application secret).
+ *
+ * @param value An hexadecimal encrypted string
+ * @return The decrypted String
+ */
+ public String decryptAES(String value) {
+ return decryptAES(value, getSecretPrefix());
+ }
+
+ /**
+ * Decrypt a String with the standard AES encryption (using the ECB mode). Private key must have a length of 16
+ * bytes.
+ *
+ * @param value An hexadecimal encrypted string
+ * @param privateKey The key used to encrypt
+ * @return The decrypted String
+ */
+ public String decryptAES(String value, String privateKey) {
+ try {
+ byte[] raw = privateKey.getBytes(UTF_8);
+ SecretKeySpec skeySpec = new SecretKeySpec(raw, AES_ECB_ALGORITHM);
+ Cipher cipher = Cipher.getInstance(AES_ECB_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec);
+ return new String(cipher.doFinal(Hex.decodeHex(value.toCharArray())), UTF_8);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Gets the 16 first characters of the application secret.
+ *
+ * @return the secret prefix.
+ */
+ private String getSecretPrefix() {
+ return secret.substring(0, 16);
+ }
+
+ /**
+ * Gets a segment of the application secret of 16 characters and encoded them in hexadecimal. The segment
+ * contains from the 16th to the 32th characters from the application secret (16 characters). The extracted
+ * segment is encoded in hexadecimal
+ *
+ * @return the default initialization vector.
+ */
+ private String getDefaultIV() {
+ return String.valueOf(Hex.encodeHex(secret.substring(16, 32).getBytes(UTF_8)));
+ }
+
+ /**
+ * Sign a token. This produces a new token, that has this token signed with a nonce.
+ * <p/>
+ * This primarily exists to defeat the BREACH vulnerability, as it allows the token to effectively be random per
+ * request, without actually changing the value.
+ *
+ * @param token The token to sign
+ * @return The signed token
+ */
+ public String signToken(String token) {
+ long nonce = System.currentTimeMillis();
+ String joined = nonce + "-" + token;
+ return sign(joined) + "-" + joined;
+ }
+
+ /**
+ * Extract a signed token that was signed by {@link #signToken(String)}.
+ *
+ * @param token The signed token to extract.
+ * @return The verified raw token, or null if the token isn't valid.
+ */
+ public String extractSignedToken(String token) {
+ String[] chunks = token.split("-", 3);
+ String signature = chunks[0];
+ String nonce = chunks[1];
+ String raw = chunks[2];
+ if (constantTimeEquals(signature, sign(nonce + "-" + raw))) {
+ return raw;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Constant time equals method.
+ * <p/>
+ * Given a length that both Strings are equal to, this method will always run in constant time.
+ * This prevents timing attacks.
+ */
+ private boolean constantTimeEquals(String a, String b) {
+ if (a.length() != b.length()) {
+ return false;
+ } else {
+ int equal = 0;
+ for (int i = 0; i < a.length(); i++) {
+ equal = equal | a.charAt(i) ^ b.charAt(i);
+ }
+ return equal == 0;
+ }
+ }
+
+ /**
+ * Encode binary data to base64.
+ *
+ * @param value The binary data
+ * @return The base64 encoded String
+ */
+ public String encodeBase64(byte[] value) {
+ return new String(Base64.encodeBase64(value), UTF_8);
+ }
+
+ /**
+ * Decode a base64 value.
+ *
+ * @param value The base64 encoded String
+ * @return decoded binary data
+ */
+ public byte[] decodeBase64(String value) {
+ return Base64.decodeBase64(value.getBytes(UTF_8));
+ }
+
+ /**
+ * Build an hexadecimal MD5 hash for a String.
+ *
+ * @param value The String to hash
+ * @return An hexadecimal Hash
+ */
+ public String hexMD5(String value) {
+ try {
+ MessageDigest messageDigest = MessageDigest.getInstance(Hash.MD5.toString());
+ messageDigest.reset();
+ messageDigest.update(value.getBytes(UTF_8));
+ byte[] digest = messageDigest.digest();
+ return String.valueOf(Hex.encodeHex(digest));
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Build an hexadecimal SHA1 hash for a String.
+ *
+ * @param value The String to hash
+ * @return An hexadecimal Hash
+ */
+ public String hexSHA1(String value) {
+ try {
+ MessageDigest md;
+ md = MessageDigest.getInstance(Hash.SHA1.toString());
+ md.update(value.getBytes(UTF_8));
+ byte[] digest = md.digest();
+ return String.valueOf(Hex.encodeHex(digest));
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/frames/Hash.java b/ipojo/manipulator/manipulator/src/test/java/test/frames/Hash.java
new file mode 100644
index 0000000..079c131
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/frames/Hash.java
@@ -0,0 +1,42 @@
+/*
+ * #%L
+ * Wisdom-Framework
+ * %%
+ * Copyright (C) 2013 - 2014 Wisdom Framework
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package test.frames;
+
+/**
+ * Common hash algorithms.
+ */
+public enum Hash {
+
+ MD5("MD5"),
+ SHA1("SHA-1"),
+ SHA256("SHA-256"),
+ SHA512("SHA-512");
+
+ private String algorithm;
+
+ Hash(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public String toString() {
+ return this.algorithm;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java b/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java
new file mode 100644
index 0000000..9b9bfbc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java
@@ -0,0 +1,105 @@
+/*
+ * 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 test.inner;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A component containing inner classes.
+ */
+@Component
+public class ComponentWithInnerClasses{
+
+ public String doSomething() {
+ MyInnerWithANativeMethod nat = new MyInnerWithANativeMethod();
+ MyInnerClass inn = new MyInnerClass();
+ Computation compute = new Computation() {
+
+ public String compute(final String s) {
+ return "foo";
+ }
+ };
+ return nat.foo() + MyStaticInnerClass.foo() + inn.foo() + compute.compute("");
+ }
+
+ private void doSomethingPrivately() {
+
+ }
+
+ private boolean flag;
+
+ boolean getFlag() {
+ return flag;
+ }
+
+ private String test = "";
+
+ private String foo = "foo";
+
+ public static final Callable<Integer> callable = new Callable<Integer>() {
+ public Integer call() {
+ return 1;
+ }
+ };
+
+ public static int call() throws Exception {
+ return callable.call();
+ }
+
+ private class MyInnerWithANativeMethod {
+
+ public String foo() {
+ return ComponentWithInnerClasses.this.foo;
+ }
+
+ public void bar() {
+ if (! getFlag()) {
+ test.charAt(0);
+ }
+ }
+
+ public native void baz();
+
+ }
+
+ public static class MyStaticInnerClass {
+
+ public static String foo() {
+ return "foo";
+ }
+
+ public String bar() {
+ return "bar";
+ }
+
+ public native void baz();
+ }
+
+
+ private class MyInnerClass {
+ public String foo() {
+ return ComponentWithInnerClasses.this.foo;
+ }
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java b/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java
new file mode 100644
index 0000000..065af03
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java
@@ -0,0 +1,28 @@
+/*
+ * 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 test.inner;
+
+/**
+ * A simple interface intended to be implemented by an anonymous class.
+ */
+public interface Computation {
+
+ public String compute(String s);
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/inner/Example.java b/ipojo/manipulator/manipulator/src/test/java/test/inner/Example.java
new file mode 100644
index 0000000..2160838
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/inner/Example.java
@@ -0,0 +1,80 @@
+/*
+ * 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 test.inner;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: clement
+ * Date: 01/10/13
+ * Time: 14:57
+ * To change this template use File | Settings | File Templates.
+ */
+public class Example {
+
+ private String myString;
+
+ org.apache.felix.ipojo.InstanceManager __IM;
+ boolean __M1___run;
+ boolean __MFoo___run;
+
+ public void doSomething() {
+ Runnable runnable = new Runnable() {
+ public void run() {
+ if (! __M1___run) {
+ __run();
+ } else {
+ try {
+ __IM.onEntry(Example.this, "__M1___run", new Object[0]);
+ __run();
+ __IM.onExit(Example.this, "__M1___run", new Object[0]);
+ } catch (Throwable e) {
+ __IM.onError(Example.this, "__M1___run", e);
+ }
+ }
+ }
+
+ private void __run() {
+ System.out.println(myString);
+ }
+ };
+ runnable.run();
+ }
+
+ private class Foo {
+ public void run() {
+ if (! __MFoo___run) {
+ __run();
+ } else {
+ try {
+ __IM.onEntry(Example.this, "__MFoo___run", new Object[0]);
+ __run();
+ __IM.onExit(Example.this, "__MFoo___run", new Object[0]);
+ } catch (Throwable e) {
+ __IM.onError(Example.this, "__MFoo___run", e);
+ }
+ }
+ }
+
+ private void __run() {
+ System.out.println(myString);
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/ipojo/ExternalHandler.java b/ipojo/manipulator/manipulator/src/test/java/test/ipojo/ExternalHandler.java
new file mode 100644
index 0000000..1699ff7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/ipojo/ExternalHandler.java
@@ -0,0 +1,23 @@
+/*
+ * 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 test.ipojo;
+
+public @interface ExternalHandler {
+}
diff --git a/ipojo/manipulator/manipulator/src/test/resources/MANIFEST.MF b/ipojo/manipulator/manipulator/src/test/resources/MANIFEST.MF
new file mode 100644
index 0000000..8bb4036
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Export-Package: org.apache.felix.ipojo.test.scenarios.manipulation.ser
+ vice
+Test-Suite: org.apache.felix.ipojo.test.scenarios.manipulation.Manipul
+ ationTestSuite
+Built-By: clement
+Tool: Bnd-0.0.357
+Bundle-Name: iPOJO Manipulation Test Suite For Java 5
+Created-By: Apache Maven Bundle Plugin
+Build-Jdk: 1.6.0_22
+Bundle-Version: 1.5.0.SNAPSHOT
+Bnd-LastModified: 1292008458378
+Bundle-ManifestVersion: 2
+Import-Package: junit.framework,org.apache.felix.ipojo;version="1.6",o
+ rg.apache.felix.ipojo.junit4osgi,org.apache.felix.ipojo.junit4osgi.he
+ lpers,org.apache.felix.ipojo.test.scenarios.manipulation.service,org.
+ osgi.framework;version="1.5"
+Bundle-SymbolicName: tests.manipulation.java5
+
diff --git a/ipojo/manipulator/manipulator/src/test/resources/empty-metadata.xml b/ipojo/manipulator/manipulator/src/test/resources/empty-metadata.xml
new file mode 100644
index 0000000..bb8ea74
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/empty-metadata.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo" />
diff --git a/ipojo/manipulator/manipulator/src/test/resources/metadata.xml b/ipojo/manipulator/manipulator/src/test/resources/metadata.xml
new file mode 100644
index 0000000..1704860
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/metadata.xml
@@ -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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Simple provider used for manipulation analysis -->
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"
+ name="Manipulation-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Non lazzy service provider, to check instantiation -->
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"
+ name="Manipulation-ImmediateFooProviderType" immediate="true"
+ architecture="true">
+ <provides />
+ </component>
+
+ <!-- Nested & Inner classes -->
+ <component name="inners" classname="org.apache.felix.ipojo.test.scenarios.component.InnerClasses">
+ <provides>
+ <property field="privateObject"/>
+ <property field="privateInt"/>
+
+ <property field="protectedObject"/>
+ <property field="protectedInt"/>
+
+ <property field="packageObject"/>
+ <property field="packageInt"/>
+
+ <property field="publicObject"/>
+ <property field="publicInt"/>
+ </provides>
+ </component>
+</ipojo>
diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
new file mode 100644
index 0000000..a701fc0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
Binary files differ
diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar
new file mode 100644
index 0000000..456e356
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar
Binary files differ
diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar
new file mode 100644
index 0000000..45322aa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar
Binary files differ
diff --git a/ipojo/manipulator/maven-ipojo-plugin/changelog.txt b/ipojo/manipulator/maven-ipojo-plugin/changelog.txt
new file mode 100644
index 0000000..614f178
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/changelog.txt
@@ -0,0 +1,203 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3461] - Re-manipulation with annotated component produces corrupted MANIFEST
+ * [FELIX-3466] - Pojoization.directoryManipulation() does not take MANIFEST file location into account.
+ * [FELIX-3508] - IPojo Manipulator left out 'array of enums' in generated metadata
+ * [FELIX-3539] - iPOJO Manipulator failed on classes containing expanded frames
+ * [FELIX-3573] - IPojo bytecode manipulation generates a duplicate local variable
+ * [FELIX-3574] - IPojo bytecode manipulation looses method argument names
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+
+Changes from the 1.8.2 to 1.8.4
+-------------------------------
+
+** Bug
+ * [FELIX-3297] - iPOJO Manipulator throws ClassNotFoundException
+ * [FELIX-3359] - Turn around to avoid to use the split verifier on Java 7
+
+** Improvement
+ * [FELIX-3384] - Ensure maven-ipojo-plugin is thread-safe for parallel maven builds
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+
+** Bug
+ * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files
+ * [FELIX-2829] - The maven-ipojo-plugin archetype descriptor is not conform
+ * [FELIX-2833] - The maven-ipojo-plugin does not support manipulating artifact with a classifier
+ * [FELIX-3012] - "Duplicate name&signature" problem
+ * [FELIX-3098] - iPOJO new manipulator crashes when using a custom reporter
+ * [FELIX-3145] - VerifyError on Java 7
+ * [FELIX-3249] - iPOJO Bnd Plugin do not write all the metadatas in the manifest
+
+** Improvement
+ * [FELIX-3017] - The manipulator should return the original class if it's already manipulated
+ * [FELIX-3078] - Introduce resource abstraction in the iPOJO manipulator
+ * [FELIX-3079] - Adapt the Ant task and the maven plugin to use the new manipulator capabilities
+ * [FELIX-3080] - Implement a BND plugin for iPOJO
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+ * [FELIX-3204] - @Temporal should handle instantiation-time properties
+ * [FELIX-3244] - Manipulator : DefaultManifestBuilder should be more extensible
+
+
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Improvement
+ * [FELIX-2733] - The maven-ipojo-plugin should support JAR and WAR as packaging type
+ * [FELIX-2744] - Add annotations to the maven-ipojo-plugin archetype
+ * [FELIX-2755] - Allow the manipulator and the different front end to use several metadata files
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1411] - Issue on windows to find components inside bundle
+
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from the 1.4.0 to 1.4.2
+-------------------------------
+** Bug
+ * [FELIX-1411] - Issue on windows to find components inside bundle
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-1302] - Manipulator never ignore annotations
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-813] - Resolve XML-Schemas locally rather than from Internet
+ * [FELIX-846] - Enhance the iPojo maven plugin to take metadata from pom.
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * Embed the latest manipulator
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/manipulator/maven-ipojo-plugin/pom.xml b/ipojo/manipulator/maven-ipojo-plugin/pom.xml
new file mode 100644
index 0000000..7f1b1da
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/pom.xml
@@ -0,0 +1,157 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Maven Plugin</name>
+ <packaging>maven-plugin</packaging>
+
+ <description>
+ Maven Plugin to package iPOJO-powered bundles.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-maven-plug-in.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0.4</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-archiver</artifactId>
+ <version>2.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ <version>3.0.16</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>2.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <!-- exclude the archetype -->
+ <exclude>src/main/resources/archetype-resources/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..8104839
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,10 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The Codehaus (http://www.codehaus.org)
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1 @@
+
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java b/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java
new file mode 100644
index 0000000..265077d
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java
@@ -0,0 +1,310 @@
+/*
+ * 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.plugin;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Classpath;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Packages an OSGi jar "bundle" as an "iPOJO bundle".
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @version $Rev$, $Date$
+ * @goal ipojo-bundle
+ * @phase package
+ * @requiresDependencyResolution test
+ * @description manipulate an OSGi bundle jar to build an iPOJO bundle
+ * @threadSafe
+ */
+public class ManipulatorMojo extends AbstractMojo {
+
+ /**
+ * The directory for the generated JAR.
+ *
+ * @parameter expression="${project.build.directory}"
+ * @required
+ */
+ private String m_buildDirectory;
+
+ /**
+ * The directory containing generated classes.
+ *
+ * @parameter expression="${project.build.outputDirectory}"
+ * @required
+ * @readonly
+ */
+ private File m_outputDirectory;
+
+ /**
+ * Location of the metadata file or iPOJO metadata configuration.
+ *
+ * @parameter alias="metadata"
+ */
+ private String m_metadata;
+
+ /**
+ * If set, the manipulated jar will be attached to the project as a separate artifact.
+ *
+ * @parameter alias="classifier" expression="${ipojo.classifier}"
+ */
+ private String m_classifier;
+
+ /**
+ * If set, select the manipulated artifact using this classifier.
+ *
+ * @parameter alias="input-classifier"
+ */
+ private String m_inputClassifier;
+
+ /**
+ * The Maven project.
+ *
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ private MavenProject m_project;
+
+ /**
+ * Used for attaching new artifacts.
+ *
+ * @component
+ * @required
+ */
+ private MavenProjectHelper m_helper;
+
+ /**
+ * Project types which this plugin supports.
+ *
+ * @parameter
+ */
+ private List<String> m_supportedProjectTypes = Arrays.asList(new String[]{"bundle", "jar", "war"});
+
+ /**
+ * Ignore annotations parameter.
+ *
+ * @parameter alias="ignoreAnnotations" default-value="false"
+ */
+ private boolean m_ignoreAnnotations;
+
+ /**
+ * Ignore embedded XSD parameter.
+ *
+ * @parameter alias="IgnoreEmbeddedSchemas" default-value="false"
+ */
+ private boolean m_ignoreEmbeddedXSD;
+
+ private boolean isXML() {
+ return m_metadata != null && (m_metadata.indexOf('<') > -1);
+ }
+
+ /**
+ * Execute method : this method launches the pojoization.
+ *
+ * @throws MojoExecutionException : an exception occurs during the manipulation.
+ * @see org.apache.maven.plugin.AbstractMojo#execute()
+ */
+ public void execute() throws MojoExecutionException {
+ // ignore project types not supported, useful when the plugin is configured in the parent pom
+ if (!this.m_supportedProjectTypes.contains(m_project.getArtifact().getType())) {
+ this.getLog().debug("Ignoring project "
+ + m_project.getArtifact() + " : type " + m_project.getArtifact().getType()
+ + " is not supported by iPOJO plugin, supported types are " + this.m_supportedProjectTypes);
+ return;
+ }
+
+ initializeSaxDriver();
+
+ getLog().info("Start bundle manipulation");
+
+ // Get metadata
+ // Check if metadata are contained in the configuration
+ File metadata = null; // Metadata File or directory containing the metadata files.
+ InputStream is = null; //Use if contained in the configuration
+
+ // Create the ClassPath and classloader.
+ Set<Artifact> artifacts = m_project.getArtifacts();
+ Set<String> urls = new LinkedHashSet<String>();
+ File classes = new File(m_project.getBasedir(), "target/classes");
+ if (classes.isDirectory()) {
+ urls.add(classes.getAbsolutePath());
+ }
+ for (Artifact artifact : artifacts) {
+ File file = artifact.getFile();
+ if (file != null && file.isFile()) {
+ urls.add(file.getAbsolutePath());
+ }
+ }
+ getLog().debug("Compute classpath: " + urls);
+ Classpath classpath = new Classpath(urls);
+
+ if (isXML()) {
+ is = new ByteArrayInputStream(m_metadata.getBytes());
+ } else {
+ // If the metadata is not set,
+ // first check if ./src/main/ipojo exists, if so look into it.
+ if (m_metadata == null) {
+ File m = new File(m_project.getBasedir(), "src/main/ipojo");
+ if (m.isDirectory()) {
+ metadata = m;
+ getLog().info("Metadata directory : " + metadata.getAbsolutePath());
+ } else {
+ // Else check target/classes/metadata.xml
+ File meta = new File(m_outputDirectory + File.separator + "metadata.xml");
+ if (!meta.exists()) {
+ // If it still does not exist, try ./metadata.xml
+ meta = new File(m_project.getBasedir() + File.separator + "metadata.xml");
+ }
+
+ if (meta.exists()) {
+ metadata = meta;
+ getLog().info("Metadata file : " + metadata.getAbsolutePath());
+ }
+
+ // No metadata.
+ }
+ } else {
+ // metadata path set.
+ File m = new File(m_project.getBasedir(), m_metadata);
+ if (!m.exists()) {
+ throw new MojoExecutionException("The metadata file does not exist : " + m.getAbsolutePath());
+ }
+ metadata = m;
+ if (m.isDirectory()) {
+ getLog().info("Metadata directory : " + metadata.getAbsolutePath());
+ } else {
+ getLog().info("Metadata file : " + metadata.getAbsolutePath());
+ }
+ }
+
+ if (metadata == null) {
+ // Verify if annotations are ignored
+ if (m_ignoreAnnotations) {
+ getLog().info("No metadata file found - ignoring annotations");
+ return;
+ } else {
+ getLog().info("No metadata file found - trying to use only annotations");
+ }
+ }
+ }
+
+ // Get input bundle, we use the already create artifact.
+ File in = null;
+ if (m_inputClassifier == null) {
+ in = m_project.getArtifact().getFile();
+ getLog().info("Input Bundle File : " + in.getAbsolutePath());
+ if (!in.exists()) {
+ throw new MojoExecutionException("The specified bundle file does not exist : " + in.getAbsolutePath());
+ }
+ } else {
+ // Look from attached artifacts.
+ @SuppressWarnings("unchecked")
+ List<Artifact> attached = m_project.getAttachedArtifacts();
+ for (int i = 0; in == null && attached != null && i < attached.size(); i++) {
+ Artifact artifact = attached.get(i);
+ if (artifact.hasClassifier() && m_inputClassifier.equals(artifact.getClassifier())) {
+ in = artifact.getFile();
+ }
+ }
+
+ if (in == null) {
+ throw new MojoExecutionException("Cannot find the file to manipulate, " +
+ "no attached artifact with classifier " + m_inputClassifier);
+ }
+
+ getLog().info("Input Bundle File : " + in.getAbsolutePath());
+ if (!in.exists()) {
+ throw new MojoExecutionException("The specified bundle file does not exist : " + in.getAbsolutePath());
+ }
+ }
+
+ File out = new File(m_buildDirectory + File.separator + "_out.jar");
+
+ Reporter reporter = new MavenReporter(getLog());
+ Pojoization pojo = new Pojoization(reporter);
+ if (m_ignoreAnnotations) {
+ pojo.disableAnnotationProcessing();
+ }
+ if (!m_ignoreEmbeddedXSD) {
+ pojo.setUseLocalXSD();
+ }
+
+ // Executes the pojoization.
+ if (is == null) {
+ if (metadata == null) { // No metadata.
+ pojo.pojoization(in, out, (File) null, classpath.createClassLoader()); // Only annotations
+ } else {
+ pojo.pojoization(in, out, metadata, classpath.createClassLoader()); // Metadata set
+ }
+ } else { // In-Pom metadata.
+ pojo.pojoization(in, out, is, classpath.createClassLoader());
+ }
+
+ for (int i = 0; i < reporter.getWarnings().size(); i++) {
+ getLog().warn((String) reporter.getWarnings().get(i));
+ }
+ if (reporter.getErrors().size() > 0) {
+ throw new MojoExecutionException((String) reporter.getErrors().get(0));
+ }
+
+ if (m_classifier != null) {
+ // The user want to attach the resulting jar
+ // Do not delete in File
+ m_helper.attachArtifact(m_project, "jar", m_classifier, out);
+ } else {
+ // Usual behavior
+ if (in.delete()) {
+ if (!out.renameTo(in)) {
+ getLog().warn("Cannot rename the manipulated jar file");
+ }
+ } else {
+ getLog().warn("Cannot delete the input jar file");
+ }
+ }
+ getLog().info("Bundle manipulation - SUCCESS");
+ }
+
+ /**
+ * If Maven runs with Java 1.4, we should use the Maven Xerces.
+ * To achieve that, we set the org.xml.sax.driver property.
+ * Otherwise, the JVM sets the org.xml.sax.driver property.
+ */
+ private void initializeSaxDriver() {
+ String version = (String) System.getProperty("java.vm.version");
+ if (version.startsWith("1.4")) {
+ getLog().info("Set the Sax driver to org.apache.xerces.parsers.SAXParser");
+ System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java b/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java
new file mode 100644
index 0000000..6afdf97
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java
@@ -0,0 +1,86 @@
+/*
+ * 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.plugin;
+
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * A {@code MavenReporter} wraps a maven logging system into an iPOJO Reporter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MavenReporter extends EmptyReporter {
+
+ /**
+ * Maven logger.
+ */
+ private Log log;
+
+ public MavenReporter(Log log) {
+ this.log = log;
+ }
+
+ @Override
+ public void trace(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable t = getThrowable(args);
+ if (t != null) {
+ log.debug(formatted, t);
+ } else {
+ log.debug(formatted);
+ }
+ }
+
+ @Override
+ public void info(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable t = getThrowable(args);
+ if (t != null) {
+ log.info(formatted, t);
+ } else {
+ log.info(formatted);
+ }
+ }
+
+ @Override
+ public void warn(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable t = getThrowable(args);
+ if (t != null) {
+ log.warn(formatted, t);
+ } else {
+ log.warn(formatted);
+ }
+ getWarnings().add(formatted);
+ }
+
+ @Override
+ public void error(String message, Object... args) {
+ String formatted = String.format(message, getMessageArguments(args));
+ Throwable t = getThrowable(args);
+ if (t != null) {
+ log.error(formatted, t);
+ } else {
+ log.error(formatted);
+ }
+ getErrors().add(formatted);
+ }
+}
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/META-INF/maven/archetype-metadata.xml b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 0000000..513ca70
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<archetype-descriptor xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ name="maven-ipojo-plugin">
+
+ <fileSets>
+ <fileSet filtered="true" packaged="true" encoding="UTF-8">
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.java</include>
+ <include>**/*.txt</include>
+ </includes>
+ </fileSet>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </fileSet>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory></directory>
+ <includes>
+ <include>*.properties</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+
+</archetype-descriptor>
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/bundle.properties b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/bundle.properties
new file mode 100644
index 0000000..9a167ce
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/bundle.properties
@@ -0,0 +1,4 @@
+# Configure the created bundle
+private.packages=${package}
+import.packages=*
+export.package=*
\ No newline at end of file
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/pom.xml b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/pom.xml
new file mode 100644
index 0000000..d27c0ea
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,75 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <groupId>${groupId}</groupId>
+ <artifactId>${artifactId}</artifactId>
+ <version>${version}</version>
+
+ <name>${artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.1.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package>${private.packages}</Private-Package>
+ <Import-Package>${import.packages}</Import-Package> <!-- defined in bundle.properties -->
+ <Export-Package>${export.packages}</Export-Package> <!-- define in bundle.properties -->
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <!-- Simply read properties from file -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>properties-maven-plugin</artifactId>
+ <version>1.0-alpha-2</version>
+ <executions>
+ <execution>
+ <phase>initialize</phase>
+ <goals>
+ <goal>read-project-properties</goal>
+ </goals>
+ <configuration>
+ <files>
+ <file>bundle.properties</file>
+ </files>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/HelloComponent.java b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/HelloComponent.java
new file mode 100644
index 0000000..9ee85e0
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/HelloComponent.java
@@ -0,0 +1,14 @@
+package ${package};
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+
+@Component
+@Instantiate
+public class HelloComponent {
+
+ public HelloComponent() {
+ System.out.println("Hello ${artifactId}");
+ }
+
+}
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/source.txt b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/source.txt
new file mode 100644
index 0000000..0198756
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/java/source.txt
@@ -0,0 +1 @@
+PUT YOUR SOURCE FILES HERE
\ No newline at end of file
diff --git a/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/resources/metadata.xml b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/resources/metadata.xml
new file mode 100644
index 0000000..456c9e6
--- /dev/null
+++ b/ipojo/manipulator/maven-ipojo-plugin/src/main/resources/archetype-resources/src/main/resources/metadata.xml
@@ -0,0 +1,16 @@
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <!--
+ Declare your component types and instances here
+ -->
+
+ <!--
+
+ <component classname="$YOUR_COMPONENT_CLASS">
+
+ </component>
+ <instance component="$YOUR_COMPONENT_CLASS" />
+
+ -->
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/manipulator/online-manipulator/changelog.txt b/ipojo/manipulator/online-manipulator/changelog.txt
new file mode 100644
index 0000000..54a513f
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/changelog.txt
@@ -0,0 +1,133 @@
+Changes from the 1.12.0 to 1.12.1
+---------------------------------
+
+** Bug
+ * [FELIX-4612] - @PostRegistration is not being called
+ * [FELIX-4620] - Warning should be removed when @Configuration is used
+ * [FELIX-4668] - Can not use @Stereotype annotated annotation from another bundle (unless its package is included or re-exported)
+ * [FELIX-4725] - Inner Class Manipulation uses the wrong 'access level'
+
+Changes from the 1.11.2 to 1.12.0
+---------------------------------
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+
+Changes from the 1.11.1 to 1.11.2
+---------------------------------
+
+ ** Bug
+ * [FELIX-4453] - Introduce manipulator BOM (Bill of Material)
+
+ ** Improvement
+ * [FELIX-4454] - Online manipulator should be able to take advantage of Stereotypes
+
+Changes from the 1.11.0 to 1.11.1
+---------------------------------
+
+** Bug
+ * [FELIX-4340] - Flex iPOJO online manipulator error if metadata.xml file not supplied
+ * [FELIX-4347] - should ignore inner classes that are assigned to static fields
+
+Changes from the 1.10.1 to 1.11.0
+---------------------------------
+
+** Bug
+ * [FELIX-4021] - maven-ipojo-plugin fails on WAR packaging
+ * [FELIX-4219] - Variables named not stored in bytecode for constructors during manipulation
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+
+** Improvement
+ * [FELIX-4112] - Add meta annotations for handler description
+ * [FELIX-4269] - Introduce an enumeration to configure binding policy from the annotation
+
+** Task
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4155] - Update bnd-ipojo-plugin for bndlib 2.x
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4253] - Add methods from inner classes in the metadata collected during the manipulation
+ * [FELIX-4254] - Specify the method id of methods from inner class
+ * [FELIX-4255] - Extend the inner class manipulation to allow method interception
+ * [FELIX-4256] - Avoid manipulation native and static methods from inner classes
+
+Changes from the 1.10.0 to 1.10.1
+---------------------------------
+
+** Bug
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4091] - Bnd iPOJO Plugin only browse classes annotated with some iPOJO annotations
+ * [FELIX-4093] - Dependency is ignored if @Bind does not respect naming pattern
+ * [FELIX-4110] - @ServiceProperty and @StaticServiceProperty are missing the immutable attribute
+
+** Improvement
+ * [FELIX-4094] - Recognize add/remove method naming pattern
+
+** New Feature
+ * [FELIX-4095] - Add CDI-like @Stereotype
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+
+Changes from the 1.8.6 to 1.10.0
+--------------------------------
+
+** Bug
+ * [FELIX-3827] - Error in bbd-ipojo-plugin of manipulating jar with embedded dependencies with maven bundle plugin + bnd-ipojo-plugin
+ * [FELIX-3900] - @HandlerDeclaration do not convert DOM Attributes to iPOJO Attributes correctly
+ * [FELIX-3938] - maven-ipojo-plugin does not behave as bnd-ipojo-plugin
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4027] - The iPOJO Ant task requires org.objectweb.asm.tree
+ * [FELIX-4046] - Inner class manipulation fails with expanded frames
+ * [FELIX-4052] - Instance declaration not created correctly when using @Instantiate if the @Component specifies a name
+
+** Improvement
+ * [FELIX-3286] - Update POM to use the new parent
+ * [FELIX-3452] - Extending maven-ipojo-plugin with directoryManipulation support.
+ * [FELIX-3749] - Refactor the manipulator for better (and extensible) annotation support
+ * [FELIX-3837] - PojoizationPlugin should be more extensible
+ * [FELIX-3901] - Avoid converting Xml namespace declaration with @HandlerDeclaration
+ * [FELIX-3927] - Exclude iPOJO 2.0 packages during manipulation
+
+** New Feature
+ * [FELIX-3699] - Allow annotations to handle custom component definitions.
+ * [FELIX-4059] - Provide a CLI tool to manipulate iPOJO bundles
+
+** Task
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3976] - Move the online manipulator out of the core bundle
+
+Changes from the 1.4.2 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from the 1.4.0 to 1.4.2
+-------------------------------
+** Bug
+ * [FELIX-1518] - iPOJO manipulator is really slow even when annotation are ignored
+
+
+Version 1.4.0
+-------------
+** Improvement
+ * Update parent pom
+ * Initial commit
+
+
diff --git a/ipojo/manipulator/online-manipulator/pom.xml b/ipojo/manipulator/online-manipulator/pom.xml
new file mode 100644
index 0000000..f18bc5d
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/pom.xml
@@ -0,0 +1,189 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO - Online Manipulator</name>
+ <artifactId>org.apache.felix.ipojo.manipulator.online</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <description>
+ iPOJO online manipulator allowing install time manipulation of iPOJO bundle.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/apache-felix-ipojo-online-manipulator.html
+ </url>
+
+ <properties>
+ <ipojo.import.packages>[1.12.1,2.0.0)</ipojo.import.packages>
+ <ipojo.manipulator.version>${project.version}</ipojo.manipulator.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-manipulator-bom</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.0</version>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ <testTarget>1.5</testTarget>
+ <testSource>1.5</testSource>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Private-Package>org.apache.felix.ipojo.online.manipulator</Private-Package>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/apache-felix-ipojo-online-manipulator.html
+ </Bundle-DocURL>
+ <Export-Package>
+ org.apache.felix.ipojo.manipulation*; version="${ipojo.manipulator.version}",
+ org.apache.felix.ipojo.xml.parser; version="${ipojo.manipulator.version}",
+ org.apache.felix.ipojo.manipulator*; version="${ipojo.manipulator.version}",
+ org.apache.felix.ipojo.annotations*; version="${ipojo.manipulator.version}",
+ </Export-Package>
+ <Private-Package>
+ org.objectweb.asm,
+ org.objectweb.asm.commons,
+ org.objectweb.asm.signature,
+ org.objectweb.asm.tree*,
+ org.objectweb.asm.util,
+ org.apache.felix.ipojo.online.manipulator
+ </Private-Package>
+ <Import-Package>!sun.io, org.osgi.framework;version=1.3, *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>${project.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>src/main/resources/META-INF/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..844c77e
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,21 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/LICENSE b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..194131d
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Online Manipulator:
+
+The Apache Felix iPOJO Online Manipulator includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..016e60d
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BridgeClassLoader.java b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BridgeClassLoader.java
new file mode 100644
index 0000000..28987a8
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BridgeClassLoader.java
@@ -0,0 +1,65 @@
+/*
+ * 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.online.manipulator;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * A classloader trying to load classes from a given jar files and then from bundles.
+ * This classloader must only be used for the iPOJO manipulator (in order to compute bytecode frames).
+ */
+public class BridgeClassLoader extends ClassLoader {
+
+ private final URLClassLoader m_loader;
+ private final BundleContext m_context;
+
+ public BridgeClassLoader(File original, BundleContext context) throws MalformedURLException {
+ m_loader = new URLClassLoader(new URL[]{original.toURI().toURL()}, null);
+ m_context = context;
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ // Try to load it using the url classloader
+ try {
+ return m_loader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ // Not there, try somewhere else.
+ }
+
+ for (Bundle bundle : m_context.getBundles()) {
+ if (bundle.getState() >= Bundle.RESOLVED) {
+ try {
+ return bundle.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ // Try next one.
+ }
+ }
+ }
+
+ // Still nothing, delegate to parent
+ return super.loadClass(name);
+ }
+}
diff --git a/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BundleAwareJarFileResourceStore.java b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BundleAwareJarFileResourceStore.java
new file mode 100644
index 0000000..0b8f612
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/BundleAwareJarFileResourceStore.java
@@ -0,0 +1,91 @@
+/*
+ * 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.online.manipulator;
+
+import static java.lang.String.format;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+import java.util.jar.JarFile;
+
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.store.JarFileResourceStore;
+import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ * User: guillaume
+ * Date: 28/02/2014
+ * Time: 19:16
+ */
+public class BundleAwareJarFileResourceStore extends JarFileResourceStore {
+
+ private final BundleContext bundleContext;
+
+ /**
+ * @param source original Bundle
+ * @param target File where the updated Bundle will be outputted
+ * @throws java.io.IOException if there is an error retrieving the Manifest from the original JarFile
+ */
+ public BundleAwareJarFileResourceStore(final JarFile source,
+ final File target,
+ final BundleContext bundleContext) throws IOException {
+ super(source, target);
+ this.bundleContext = bundleContext;
+ DefaultManifestBuilder manifestBuilder = new DefaultManifestBuilder();
+ manifestBuilder.setMetadataRenderer(new MetadataRenderer());
+ setManifestBuilder(manifestBuilder);
+ }
+
+ @Override
+ public byte[] read(final String path) throws IOException {
+ try {
+ return super.read(path);
+ } catch (IOException e) {
+ // An IOException is thrown when no resource can be found
+ // We swallow this exception and try to load the resource from the installed bundles
+ }
+
+ String directory = path.substring(0, path.lastIndexOf('/'));
+ String filename = path.substring(path.lastIndexOf('/') + 1);
+
+ for (Bundle bundle : bundleContext.getBundles()) {
+
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ List<URL> entries = wiring.findEntries(directory, filename, 0);
+ for (URL url : entries) {
+ try {
+ return Streams.readBytes(url.openStream());
+ } catch (IOException e) {
+ // Ignore and move to the next source
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ throw new IOException(format("Could not find %s in currently available bundles", path));
+ }
+}
diff --git a/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/Files.java b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/Files.java
new file mode 100644
index 0000000..f645651
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/Files.java
@@ -0,0 +1,54 @@
+/*
+ * 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.online.manipulator;
+
+import static org.apache.felix.ipojo.manipulator.util.Streams.close;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * User: guillaume
+ * Date: 04/03/2014
+ * Time: 15:33
+ */
+public class Files {
+
+ public static void dump(URL url, File target) throws IOException {
+ dump(url.openStream(), target);
+ }
+
+ public static void dump(InputStream stream, File target) throws IOException {
+ BufferedInputStream in = new BufferedInputStream(stream);
+ FileOutputStream file = new FileOutputStream(target);
+ BufferedOutputStream out = new BufferedOutputStream(file);
+ int i;
+ while ((i = in.read()) != -1) {
+ out.write(i);
+ }
+ out.flush();
+ close(in, out);
+ }
+}
diff --git a/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/IPOJOURLHandler.java b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/IPOJOURLHandler.java
new file mode 100644
index 0000000..dc0e838
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/IPOJOURLHandler.java
@@ -0,0 +1,313 @@
+/*
+ * 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.online.manipulator;
+
+import static java.lang.String.format;
+import static org.apache.felix.ipojo.online.manipulator.Files.dump;
+import static org.osgi.service.log.LogService.LOG_DEBUG;
+import static org.osgi.service.log.LogService.LOG_WARNING;
+import static org.osgi.service.url.URLConstants.URL_HANDLER_PROTOCOL;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Invalidate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.CompositeMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.FileMetadataProvider;
+import org.apache.felix.ipojo.manipulator.reporter.SystemReporter;
+import org.apache.felix.ipojo.manipulator.spi.ModuleProvider;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+import org.apache.felix.ipojo.manipulator.spi.provider.CompositeModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.provider.CoreModuleProvider;
+import org.apache.felix.ipojo.manipulator.spi.provider.DefaultModuleProvider;
+import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor;
+import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.url.AbstractURLStreamHandlerService;
+import org.osgi.service.url.URLStreamHandlerService;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * iPOJO URL Handler allowing installation time manipulation.
+ *
+ * When a bundle is installed with the {@literal ipojo} URL prefix, the referred bundle is
+ * manipulated by this handler.
+
+ * The {@literal metadata.xml} file can either be provided:
+ * <ul>
+ * <li>Inside the bundle, this handler will look for {@literal /metadata.xml} (at the root of the bundle)
+ * or in {@literal /META-INF/metadata.xml}</li>
+ * <li>Through the URL using the following URL format: {@literal ipojo:URL_BUNDLE!URL_METADATA}, notice
+ * the {@literal !} used as separator</li>
+ * </ul>
+ *
+ * Examples of valid iPojo's URLs:
+ * <pre>
+ * ipojo:file:///tmp/bundle.jar
+ * ipojo:/http://www.example.org/bundle.jar
+ * ipojo://mvn://com.acme/bundle/1.0.0 (with Maven Pax Url support installed)
+ * ipojo:file:///tmp/bundle.jar!file:///tmp2/metadata.xml
+ * </pre>
+ *
+ * Notice that trailing {@literal '/'} (or {@literal '//'}) after {@literal ipojo:} are optional.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component(publicFactory = false,
+ immediate = true)
+@Provides(specifications = URLStreamHandlerService.class,
+ properties = @StaticServiceProperty(name = URL_HANDLER_PROTOCOL,
+ value = "ipojo",
+ type = "java.lang.String"))
+@Instantiate
+public class IPOJOURLHandler extends AbstractURLStreamHandlerService {
+
+ public static final String IPOJO_SCHEME = "ipojo:";
+
+ private final BundleContext m_context;
+
+ /**
+ * The directory storing manipulated bundles.
+ */
+ private final File m_temp;
+
+ private List<Module> m_modules = new ArrayList<Module>();
+
+ //@Requires(optional = true, defaultimplementation = SystemLogService.class)
+ // TODO Change this once NPE is fixed
+ private LogService logger = new SystemLogService();
+
+ @Bind(optional = true, aggregate = true)
+ public void bindModule(Module module) {
+ m_modules.add(module);
+ }
+
+ @Unbind
+ public void unbindModule(Module module) {
+ m_modules.remove(module);
+ }
+
+ /**
+ * Creates a IPOJOURLHandler.
+ * Gets the bundle context and create the working
+ * directory.
+ *
+ * @param bundleContext the bundle context
+ */
+ public IPOJOURLHandler(BundleContext bundleContext) {
+ this(bundleContext, bundleContext.getDataFile("temp"));
+ }
+
+ public IPOJOURLHandler(BundleContext context, File work) {
+ m_context = context;
+ m_temp = work;
+ if (!m_temp.exists()) {
+ m_temp.mkdir();
+ }
+ }
+
+ /**
+ * Stops the URL handler:
+ * Deletes the working directory.
+ */
+ @Invalidate
+ public void stop() {
+ File[] files = m_temp.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ files[i].delete();
+ }
+ }
+ m_temp.delete();
+ }
+
+ /**
+ * Opens a connection using the ipojo url handler.
+ * This methods parses the URL and manipulate the given bundle.
+ *
+ * @param url the url.
+ * @return the URL connection on the manipulated bundle
+ * @throws java.io.IOException occurs when the bundle cannot be either downloaded, or manipulated or
+ * installed correctly.
+ * @see org.osgi.service.url.AbstractURLStreamHandlerService#openConnection(java.net.URL)
+ */
+ public URLConnection openConnection(URL url) throws IOException {
+ logger.log(LOG_DEBUG, format("Processing URL %s", url));
+ String full = removeScheme(url);
+
+ // Now full is like : URL!URL or URL
+ String[] urls = full.split("!");
+ URL bundleURL = null;
+ URL metadataURL = null;
+ if (urls.length == 1) {
+ // URL form
+ bundleURL = new URL(urls[0]);
+ } else if (urls.length == 2) {
+ // URL!URL form
+ bundleURL = new URL(urls[0]);
+ metadataURL = new URL(urls[1]);
+ } else {
+ throw new MalformedURLException("The iPOJO url is not formatted correctly, ipojo:bundle_url[!metadata_url] expected");
+ }
+
+ logger.log(LOG_DEBUG, format("Extracted URL %s", url));
+
+ // Dump the referenced bundle on disk
+ File original = File.createTempFile("original-", ".jar", m_temp);
+ dump(bundleURL.openStream(), original);
+
+ JarFile jf = new JarFile(original);
+
+ File metadata = null;
+ if (metadataURL != null) {
+ metadata = File.createTempFile("ipojo-", ".xml", m_temp);
+ dump(metadataURL, metadata);
+ } else {
+ // Check that the metadata are in the jar file
+ metadata = findMetadata(jf);
+ }
+
+ Reporter reporter = new SystemReporter();
+ File out = File.createTempFile("ipojo-", ".jar", m_temp);
+
+ ResourceStore store = new BundleAwareJarFileResourceStore(jf, out, m_context);
+
+ CompositeMetadataProvider composite = new CompositeMetadataProvider(reporter);
+ if (metadata != null) {
+ FileMetadataProvider provider = new FileMetadataProvider(metadata, reporter);
+ composite.addMetadataProvider(provider);
+ }
+
+ ClassLoader classloader = new BridgeClassLoader(original, m_context);
+ // Pojoization
+ Pojoization pojoizator = new Pojoization(createModuleProvider());
+ try {
+ pojoizator.pojoization(store, composite, createVisitor(store, reporter), classloader);
+ } catch (Exception e) {
+ if (!pojoizator.getErrors().isEmpty()) {
+ throw new IOException("Errors occurred during the manipulation : " + pojoizator.getErrors(), e);
+ }
+ e.printStackTrace();
+ throw new IOException("Cannot manipulate the Url: " + url, e);
+ }
+
+ if (!pojoizator.getErrors().isEmpty()) {
+ throw new IOException("Errors occurred during the manipulation : " + pojoizator.getErrors());
+ }
+ if (!pojoizator.getWarnings().isEmpty()) {
+ logger.log(LOG_WARNING, format("Warnings occurred during the manipulation %s", pojoizator.getWarnings()));
+ }
+
+ logger.log(LOG_DEBUG, format("Manipulation done %s", out.exists()));
+
+ // Cleanup
+ if (metadata != null) {
+ metadata.delete();
+ }
+ original.delete();
+ out.deleteOnExit();
+
+ // Returns the URL Connection
+ return out.toURI().toURL().openConnection();
+
+
+ }
+
+ private String removeScheme(final URL url) {
+ String full = url.toExternalForm();
+ // Remove ipojo:
+ if (full.startsWith(IPOJO_SCHEME)) {
+ full = full.substring(IPOJO_SCHEME.length());
+ }
+ // Remove '/' or '//'
+ while (full.startsWith("/")) {
+ full = full.substring(1);
+ }
+
+ return full.trim();
+ }
+
+ private ManipulationVisitor createVisitor(ResourceStore store, Reporter reporter) {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(reporter);
+ writer.setResourceStore(store);
+
+ CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer);
+ checkFieldConsistencyVisitor.setReporter(reporter);
+ return checkFieldConsistencyVisitor;
+ }
+
+
+ private ModuleProvider createModuleProvider() {
+ return new CompositeModuleProvider(
+ new CoreModuleProvider(),
+ new DefaultModuleProvider(m_modules)
+ );
+ }
+
+ /**
+ * Looks for the metadata.xml file in the jar file.
+ * Two locations are checked:
+ * <ol>
+ * <li>the root of the jar file</li>
+ * <li>the META-INF directory</li>
+ * </ol>
+ *
+ * @param jar the jar file
+ * @return the found file or <code>null</code> if not found.
+ * @throws java.io.IOException occurs when the Jar file cannot be read.
+ */
+ private File findMetadata(JarFile jar) throws IOException {
+ JarEntry je = jar.getJarEntry("metadata.xml");
+ if (je == null) {
+ je = jar.getJarEntry("META-INF/metadata.xml");
+ }
+
+ if (je == null) {
+ logger.log(LOG_DEBUG, "Metadata file not found, use annotations only.");
+ return null; // Not Found, use annotation only
+ } else {
+ logger.log(LOG_DEBUG, format("Metadata file found at %s", je.getName()));
+ File metadata = File.createTempFile("ipojo-", ".xml", m_temp);
+ dump(jar.getInputStream(je), metadata);
+ logger.log(LOG_DEBUG, format("Metadata file saved at %s", metadata));
+ return metadata;
+ }
+
+ }
+
+}
diff --git a/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/SystemLogService.java b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/SystemLogService.java
new file mode 100644
index 0000000..f147d84
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/java/org/apache/felix/ipojo/online/manipulator/SystemLogService.java
@@ -0,0 +1,83 @@
+/*
+ * 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.online.manipulator;
+
+import static java.lang.String.format;
+
+import java.io.PrintStream;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+* Default implementation based on System.out
+*/
+public class SystemLogService implements LogService {
+
+ public void log(final int level, final String message) {
+ log(null, level, message, null);
+ }
+
+ public void log(final int level, final String message, final Throwable throwable) {
+ log(null, level, message, throwable);
+ }
+
+ public void log(final ServiceReference reference, final int level, final String message) {
+ log(null, level, message, null);
+ }
+
+ public void log(final ServiceReference reference, final int level, final String message, final Throwable throwable) {
+ PrintStream stream = System.out;
+ if (level >= LogService.LOG_WARNING) {
+ stream = System.err;
+ }
+
+ String formatted = format("%s %s", asString(level), message);
+
+ if (reference != null) {
+ formatted = format("[%s] %s", reference.getBundle().getSymbolicName(), formatted);
+ }
+
+ // Print the message
+ stream.println(formatted);
+ if (throwable != null) {
+ throwable.printStackTrace(stream);
+ }
+ }
+
+ private static String asString(final int level) {
+ String levelStr = "?";
+ switch (level) {
+ case LOG_DEBUG:
+ levelStr = "D";
+ break;
+ case LOG_INFO:
+ levelStr = "I";
+ break;
+ case LOG_WARNING:
+ levelStr = "W";
+ break;
+ case LOG_ERROR:
+ levelStr = "E";
+ break;
+ }
+ return levelStr;
+ }
+}
diff --git a/ipojo/manipulator/online-manipulator/src/main/resources/META-INF/constants.properties b/ipojo/manipulator/online-manipulator/src/main/resources/META-INF/constants.properties
new file mode 100644
index 0000000..d070319
--- /dev/null
+++ b/ipojo/manipulator/online-manipulator/src/main/resources/META-INF/constants.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# This file define the different constant we use in the manipulator. This file is filtered by Maven.
+manipulator.version=${project.version}
+ipojo.import.packages=${ipojo.import.packages}
\ No newline at end of file
diff --git a/ipojo/manipulator/pom.xml b/ipojo/manipulator/pom.xml
new file mode 100644
index 0000000..538fe6e
--- /dev/null
+++ b/ipojo/manipulator/pom.xml
@@ -0,0 +1,69 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.manipulator-project</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Manipulator Project</name>
+ <packaging>pom</packaging>
+
+ <description>
+ The iPOJO Manipulator project contains the iPOJO packaging process and
+ several front-ends for Ant, Maven and BND.
+ </description>
+
+ <modules>
+ <module>manipulator-bom</module>
+ <module>annotations</module>
+ <module>manipulator</module>
+ <module>manipulator-it</module>
+ <module>ipojo-ant-task</module>
+ <module>maven-ipojo-plugin</module>
+ <module>bnd-ipojo-plugin</module>
+ <module>online-manipulator</module>
+ </modules>
+
+ <scm>
+ <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
+ <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <tagBase>https://svn.apache.org/repos/asf/felix/releases</tagBase>
+ <useReleaseProfile>false</useReleaseProfile>
+ <goals>deploy</goals>
+ <arguments>-Papache-release</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ipojo/manipulator/src/main/appended-resources/META-INF/NOTICE b/ipojo/manipulator/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/manipulator/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/metadata/changelog.txt b/ipojo/metadata/changelog.txt
new file mode 100644
index 0000000..3c6dc74
--- /dev/null
+++ b/ipojo/metadata/changelog.txt
@@ -0,0 +1,29 @@
+Changes from 1.6.0 to 1.6.1
+---------------------------
+** Improvement
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+
+
+Changes from 1.4.0 to 1.6.0
+---------------------------
+** Improvement
+ * [FELIX-3131] - Elements and attributes should conserve the insertion order
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Improvement
+ * Update parent pom
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Improvement
+ * [FELIX-795] - Improve metadata and manipulator performance
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Improvement
+ * Update to latest version
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/metadata/pom.xml b/ipojo/metadata/pom.xml
new file mode 100644
index 0000000..732cdc7
--- /dev/null
+++ b/ipojo/metadata/pom.xml
@@ -0,0 +1,67 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+
+ <version>1.6.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Metadata</name>
+
+ <description>
+ iPOJO internal metadata model.
+ </description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Name>iPOJO Metadata</Bundle-Name>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Metadata</Bundle-Description>
+ <Export-Package>org.apache.felix.ipojo.metadata</Export-Package>
+ </instructions>
+ <obrRepository>NONE</obrRepository>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/metadata/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/metadata/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..05c68c0
--- /dev/null
+++ b/ipojo/metadata/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,10 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Third-Party Software
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Attribute.java b/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Attribute.java
new file mode 100644
index 0000000..6910068
--- /dev/null
+++ b/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Attribute.java
@@ -0,0 +1,91 @@
+/*
+ * 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.metadata;
+
+/**
+ * An attribute is a key-value pair. It represents the attribute
+ * of XML elements.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Attribute {
+
+ /**
+ * The name of the attribute.
+ */
+ private String m_name;
+
+ /**
+ * The value of the attribute.
+ */
+ private String m_value;
+
+ /**
+ * The namespace of the attribute.
+ */
+ private String m_nameSpace;
+
+ /**
+ * Creates an attribute.
+ * @param name the name of the attribute.
+ * @param value the value of the attribute.
+ */
+ public Attribute(String name, String value) {
+ m_name = name.toLowerCase();
+ m_value = value;
+ }
+
+ /**
+ * Creates an attribute.
+ * @param name the name of the attribute.
+ * @param value the value of the attribute.
+ * @param ns the namespace of the attribute.
+ */
+ public Attribute(String name, String ns, String value) {
+ m_name = name.toLowerCase();
+ m_value = value;
+ if (ns != null && ns.length() > 0) {
+ m_nameSpace = ns;
+ }
+ }
+
+ /**
+ * Gets the attribute name.
+ * @return the name
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets attribute value.
+ * @return the value
+ */
+ public String getValue() {
+ return m_value;
+ }
+
+ /**
+ * Gets attribute namespace.
+ * @return the namespace
+ */
+ public String getNameSpace() {
+ return m_nameSpace;
+ }
+
+}
diff --git a/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java b/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java
new file mode 100644
index 0000000..85e5a47
--- /dev/null
+++ b/ipojo/metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java
@@ -0,0 +1,400 @@
+/*
+ * 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.metadata;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An element represents an XML Element.
+ * It contains a name, a namepace, {@link Attribute} objects
+ * and sub-elements. This class is used to parse iPOJO metadata.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Element {
+
+ /**
+ * The name of the element.
+ */
+ private String m_name;
+
+ /**
+ * The namespace of the element.
+ */
+ private String m_nameSpace;
+
+ /**
+ * The map of attributes of the element (attribute name -> {@link Attribute}).
+ * The map key is the qualified name of the attribute (<code>ns:name</code>)
+ * The value is the attribute object.
+ */
+ private Map m_attributes = new LinkedHashMap();
+
+ /**
+ * The map of the sub-element of the element (element name -> {@link Element}.
+ * The map key is the element qualified name (ns:name).
+ * The value is the array of element of this name.
+ */
+ private Map m_elements = new LinkedHashMap();
+
+ /**
+ * Creates an Element.
+ * @param name the name of the element
+ * @param ns the namespace of the element
+ */
+ public Element(String name, String ns) {
+ m_name = name.toLowerCase();
+ if (ns != null && ns.length() > 0) {
+ m_nameSpace = ns.toLowerCase();
+ }
+ }
+
+ /**
+ * Gets sub-elements.
+ * If no sub-elements, an empty array is returned.
+ * @return the sub elements
+ */
+ public Element[] getElements() {
+ Collection col = m_elements.values();
+ Iterator it = col.iterator();
+ List list = new ArrayList();
+ while (it.hasNext()) {
+ Element[] v = (Element[]) it.next();
+ for (int i = 0; i < v.length; i++) {
+ list.add(v[i]);
+ }
+ }
+ return (Element[]) list.toArray(new Element[list.size()]);
+ }
+
+ /**
+ * Gets element attributes.
+ * If no attributes, an empty array is returned.
+ * @return the attributes
+ */
+ public Attribute[] getAttributes() {
+ return (Attribute[]) m_attributes.values().toArray(new Attribute[0]);
+ }
+
+ /**
+ * Gets element name.
+ * @return the name of the element
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets element namespace.
+ * @return the namespace of the element
+ */
+ public String getNameSpace() {
+ return m_nameSpace;
+ }
+
+ /**
+ * Returns the value of the attribute given in parameter.
+ * @param name the name of the searched attribute
+ * @return the value of the attribute given in parameter,
+ * <code>null</code> if the attribute does not exist
+ */
+ public String getAttribute(String name) {
+ name = name.toLowerCase();
+ Attribute att = (Attribute) m_attributes.get(name);
+ if (att == null) {
+ return null;
+ } else {
+ return att.getValue();
+ }
+ }
+
+ /**
+ * Returns the value of the attribute "name" of the namespace "ns".
+ * @param name the name of the attribute to find
+ * @param ns the namespace of the attribute to find
+ * @return the String value of the attribute, or
+ * <code>null</code> if the attribute is not found.
+ */
+ public String getAttribute(String name, String ns) {
+ name = ns.toLowerCase() + ":" + name.toLowerCase();
+ return getAttribute(name);
+ }
+
+ /**
+ * Gets the qualified name of the current element.
+ * @return the qualified name of the current element.
+ */
+ private String getQualifiedName() {
+ if (m_nameSpace == null) {
+ return m_name;
+ } else {
+ return m_nameSpace + ":" + m_name;
+ }
+ }
+
+ /**
+ * Adds a sub-element.
+ * @param elem the element to add
+ */
+ public void addElement(Element elem) {
+ Element[] array = (Element[]) m_elements.get(elem.getQualifiedName());
+ if (array == null) {
+ m_elements.put(elem.getQualifiedName(), new Element[] {elem});
+ } else {
+ Element[] newElementsList = new Element[array.length + 1];
+ System.arraycopy(array, 0, newElementsList, 0, array.length);
+ newElementsList[array.length] = elem;
+ m_elements.put(elem.getQualifiedName(), newElementsList);
+ }
+ }
+
+ /**
+ * Removes a sub-element.
+ * @param elem the element to remove
+ */
+ public void removeElement(Element elem) {
+ Element[] array = (Element[]) m_elements.get(elem.getQualifiedName());
+ if (array == null) {
+ return;
+ } else {
+ int idx = -1;
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] == elem) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx >= 0) {
+ if ((array.length - 1) == 0) {
+ m_elements.remove(elem.getQualifiedName());
+ } else {
+ Element[] newElementsList = new Element[array.length - 1];
+ System.arraycopy(array, 0, newElementsList, 0, idx);
+ if (idx < newElementsList.length) {
+ System.arraycopy(array, idx + 1, newElementsList, idx, newElementsList.length - idx);
+ }
+ m_elements.put(elem.getQualifiedName(), newElementsList); // Update the stored list.
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a attribute.
+ * @param att the attribute to add
+ */
+ public void addAttribute(Attribute att) {
+ String name = att.getName().toLowerCase();
+ if (att.getNameSpace() != null) {
+ name = att.getNameSpace().toLowerCase() + ":" + name;
+ }
+ m_attributes.put(name, att);
+ }
+
+ /**
+ * Removes an attribute.
+ * @param att the attribute to remove
+ */
+ public void removeAttribute(Attribute att) {
+ String name = att.getName();
+ if (att.getNameSpace() != null) {
+ name = att.getNameSpace() + ":" + name;
+ }
+ m_attributes.remove(name);
+ }
+
+ /**
+ * Gets the elements array of the element type given in parameter.
+ * This method looks for an empty namespace.
+ * @param name the type of the element to find (element name)
+ * @return the resulting element array (<code>null</code> if the search failed)
+ */
+ public Element[] getElements(String name) {
+ Element[] elems = (Element[]) m_elements.get(name.toLowerCase());
+ return elems;
+ }
+
+ /**
+ * Gets the elements array of the element type given in parameter.
+ * @param name the type of the element to find (element name)
+ * @param ns the namespace of the element
+ * @return the resulting element array (<code>null</code> if the search failed)
+ */
+ public Element[] getElements(String name, String ns) {
+ if (ns == null || ns.length() == 0) {
+ return getElements(name);
+ }
+ name = ns + ":" + name;
+ return getElements(name);
+ }
+
+ /**
+ * Does the element contain a sub-element of the type given in parameter.
+ * @param name the type of the element to check.
+ * @return <code>true</code> if the element contains an element of the type "name"
+ */
+ public boolean containsElement(String name) {
+ return m_elements.containsKey(name.toLowerCase());
+ }
+
+ /**
+ * Does the element contain a sub-element of the type given in parameter.
+ * @param name the type of the element to check.
+ * @param ns the namespace of the element to check.
+ * @return <code>true</code> if the element contains an element of the type "name"
+ */
+ public boolean containsElement(String name, String ns) {
+ if (ns != null && ns.length() != 0) {
+ name = ns + ":" + name;
+ }
+ return containsElement(name);
+ }
+
+ /**
+ * Does the element contain an attribute of the name given in parameter.
+ * @param name the name of the element
+ * @return <code>true</code> if the element contains an attribute of the type "name"
+ */
+ public boolean containsAttribute(String name) {
+ return m_attributes.containsKey(name.toLowerCase());
+ }
+
+ /**
+ * Gets the XML form of this element.
+ * @return the XML snippet representing this element.
+ */
+ public String toXMLString() {
+ return toXMLString(0);
+ }
+
+ /**
+ * Internal method to get XML form of an element.
+ * @param indent the indentation to used.
+ * @return the XML snippet representing this element.
+ */
+ private String toXMLString(int indent) {
+ StringBuffer xml = new StringBuffer();
+
+ StringBuffer tabs = new StringBuffer();
+ for (int j = 0; j < indent; j++) {
+ tabs.append("\t");
+ }
+
+ xml.append(tabs);
+ if (m_nameSpace == null) {
+ xml.append("<" + m_name);
+ } else {
+ xml.append("<" + m_nameSpace + ":" + m_name);
+ }
+
+ Set keys = m_attributes.keySet();
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ Attribute current = (Attribute) m_attributes.get(it.next());
+ if (current.getNameSpace() == null) {
+ xml.append(" " + current.getName() + "=\"" + current.getValue() + "\"");
+ } else {
+ xml.append(" " + current.getNameSpace() + ":" + current.getName() + "=\"" + current.getValue() + "\"");
+ }
+ }
+
+
+ if (m_elements.size() == 0) {
+ xml.append("/>");
+ return xml.toString();
+ } else {
+ xml.append(">");
+ keys = m_elements.keySet();
+ it = keys.iterator();
+ while (it.hasNext()) {
+ Element[] e = (Element[]) m_elements.get(it.next());
+ for (int i = 0; i < e.length; i++) {
+ xml.append("\n");
+ xml.append(e[i].toXMLString(indent + 1));
+ }
+ }
+ xml.append("\n" + tabs + "</" + m_name + ">");
+ return xml.toString();
+ }
+ }
+
+ /**
+ * To String method.
+ * @return the String form of this element.
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return toString(0);
+ }
+
+ /**
+ * Internal method to compute the toString method.
+ * @param indent the indentation to use.
+ * @return the String form of this element.
+ */
+ private String toString(int indent) {
+ StringBuffer xml = new StringBuffer();
+
+ StringBuffer tabs = new StringBuffer();
+ for (int j = 0; j < indent; j++) {
+ tabs.append("\t");
+ }
+
+ xml.append(tabs);
+ if (m_nameSpace == null) {
+ xml.append(m_name);
+ } else {
+ xml.append(m_nameSpace + ":" + m_name);
+ }
+
+ Set keys = m_attributes.keySet();
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ Attribute current = (Attribute) m_attributes.get(it.next());
+ if (current.getNameSpace() == null) {
+ xml.append(" " + current.getName() + "=\"" + current.getValue() + "\"");
+ } else {
+ xml.append(" " + current.getNameSpace() + ":" + current.getName() + "=\"" + current.getValue() + "\"");
+ }
+ }
+
+ if (m_elements.size() == 0) {
+ return xml.toString();
+ } else {
+ keys = m_elements.keySet();
+ it = keys.iterator();
+ while (it.hasNext()) {
+ Element[] e = (Element[]) m_elements.get(it.next());
+ for (int i = 0; i < e.length; i++) {
+ xml.append("\n");
+ xml.append(e[i].toString(indent + 1));
+ }
+ }
+ return xml.toString();
+ }
+ }
+
+}
diff --git a/ipojo/pom.xml b/ipojo/pom.xml
new file mode 100644
index 0000000..4778d3b
--- /dev/null
+++ b/ipojo/pom.xml
@@ -0,0 +1,85 @@
+<!--
+ 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>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>iPOJO</artifactId>
+ <name>Apache Felix iPOJO ~ Reactor</name>
+ <version>1.5.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <modules>
+ <!-- main modules -->
+ <module>metadata</module>
+ <module>manipulator</module>
+ <module>runtime</module>
+
+ <!-- handlers -->
+ <module>handler/extender</module>
+ <module>handler/temporal</module>
+ <module>handler/eventadmin</module>
+ <module>handler/whiteboard</module>
+ <module>handler/jmx</module>
+ <module>handler/transaction</module>
+
+ <!-- tools -->
+ <module>arch</module>
+ <module>webconsole-plugin</module>
+
+ <!-- distribution and tutorials -->
+ <module>distributions</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <version>1.0-alpha-3</version>
+ <configuration>
+ <excludeSubProjects>true</excludeSubProjects>
+ <excludes>
+ <param>**/*</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <aggregate>true</aggregate>
+ <show>private</show>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+</project>
diff --git a/ipojo/runtime/api/changelog.txt b/ipojo/runtime/api/changelog.txt
new file mode 100644
index 0000000..6a130a6
--- /dev/null
+++ b/ipojo/runtime/api/changelog.txt
@@ -0,0 +1,219 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.10.0 to 1.10.1
+-----------------------------
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Improvement
+ * [FELIX-2758] - Add post-registration and post-unregistration callbacks to the iPOJO API
+ * [FELIX-2759] - The iPOJO API do not support constructor injection
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+ * [FELIX-2268] - Simplify setting of properties.
+
+** New Feature
+ * [FELIX-2132] - Provides a way to control service exposition from the implementation class
+
+Version 1.4.0
+-------------
+
+** Bug
+ * [FELIX-965] - Avoid classloading issue if an already manipulated class is used by the API
+
+** Improvement
+ * Update parent pom
+ * Initial commit
+
+
diff --git a/ipojo/runtime/api/pom.xml b/ipojo/runtime/api/pom.xml
new file mode 100644
index 0000000..1ffe610
--- /dev/null
+++ b/ipojo/runtime/api/pom.xml
@@ -0,0 +1,137 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <properties>
+ <asm.version>5.0.2</asm.version>
+ </properties>
+ <artifactId>org.apache.felix.ipojo.api</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO API</name>
+
+ <description>
+ iPOJO API used to define component types and instances using Java.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/apache-felix-ipojo-api.html
+ </url>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-userguide/apache-felix-ipojo-api.html
+ </Bundle-DocURL>
+ <Import-Package>
+ org.apache.felix.ipojo.composite;resolution:=optional,
+ org.osgi.framework;version=1.3,
+ !org.apache.felix.ipojo.xml.parser,
+ !org.apache.felix.ipojo.annotations,
+ *
+ </Import-Package>
+ <Export-Package>
+ org.apache.felix.ipojo.api,
+ org.apache.felix.ipojo.api.composite,
+ org.objectweb.asm.commons;version=${asm.version};-split-package:=merge-last,
+ org.objectweb.asm;version=${asm.version};-split-package:=merge-last,
+ org.objectweb.asm.signature;version=${asm.version};-split-package:=merge-last
+ </Export-Package>
+ <Private-Package>
+ org.objectweb.asm.commons,
+ org.objectweb.asm.signature,
+ org.objectweb.asm,
+ org.objectweb.asm.tree*,
+ org.objectweb.asm.util,
+ org.apache.felix.ipojo.manipulation*,
+ org.apache.felix.ipojo.manipulator*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.7</version>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java15</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.composite</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/ipojo/runtime/api/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/api/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..e23daaf
--- /dev/null
+++ b/ipojo/runtime/api/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,16 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/api/src/main/appended-resources/META-INF/LICENSE b/ipojo/runtime/api/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..9e46ee9
--- /dev/null
+++ b/ipojo/runtime/api/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO API:
+
+The Apache Felix iPOJO API includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/runtime/api/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/api/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..016e60d
--- /dev/null
+++ b/ipojo/runtime/api/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java
new file mode 100644
index 0000000..ef4cd06
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java
@@ -0,0 +1,195 @@
+/*
+ * 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.api;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+
+
+/**
+ * The component type class allows specifying a new component type
+ * and its attached factory. It also allows creating instances form
+ * the specified component type.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class ComponentType {
+
+ /**
+ * The list of instances created from the
+ * current component type.
+ */
+ private List m_instances = new ArrayList();
+
+
+ /**
+ * Gets the factory attached to the current
+ * component type.
+ * @return the factory
+ */
+ public abstract Factory getFactory();
+
+ /**
+ * Starts the factory attached to this
+ * component type. Once started a factory
+ * and its attached component type
+ * cannot be modified.
+ */
+ public abstract void start();
+
+ /**
+ * Stops the factory attached to this
+ * component type.
+ */
+ public abstract void stop();
+
+
+ /**
+ * Creates a component instance from the current type
+ * with an empty configuration.
+ * @return the component instance object.
+ * @throws UnacceptableConfiguration the configuration is not acceptable
+ * @throws MissingHandlerException the factory in invalid
+ * @throws ConfigurationException the instance configuration failed
+ */
+ public ComponentInstance createInstance() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = ensureAndGetFactory().createComponentInstance(null);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a component instance from the current type
+ * with the given name.
+ * @param name the instance name
+ * @return the component instance object.
+ * @throws UnacceptableConfiguration the configuration is not acceptable
+ * @throws MissingHandlerException the factory in invalid
+ * @throws ConfigurationException the instance configuration failed
+ */
+ public ComponentInstance createInstance(String name) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Dictionary dict = null;
+ if (name != null) {
+ dict = new Properties();
+ dict.put("instance.name", name);
+ }
+ ComponentInstance ci = ensureAndGetFactory().createComponentInstance(dict);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a component instance from the current type
+ * with the given configuration.
+ * @param conf the configuration
+ * @return the component instance object.
+ * @throws UnacceptableConfiguration the configuration is not acceptable
+ * @throws MissingHandlerException the factory in invalid
+ * @throws ConfigurationException the instance configuration failed
+ */
+ public ComponentInstance createInstance(Dictionary conf) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ ComponentInstance ci = ensureAndGetFactory().createComponentInstance(conf);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Disposes the given name. The instance must be created from this
+ * component type.
+ * @param ci the component instance to delete
+ * @return <code>true</code> if the instance was
+ * successfully disposed.
+ */
+ public boolean disposeInstance(ComponentInstance ci) {
+ if (m_instances.remove(ci)) {
+ ci.dispose();
+ return true;
+ } else {
+ System.err.println("The instance was not created from this component type");
+ return false;
+ }
+ }
+
+ /**
+ * Gets the component instance created from this component type.
+ * with the given name.
+ * @param name the instance name.
+ * @return the component instance with the given name and created
+ * from the current component type factory. <code>null</code> if
+ * the instance cannot be found.
+ */
+ public ComponentInstance getInstanceByName(String name) {
+ for (int i = 0; i < m_instances.size(); i++) {
+ ComponentInstance ci = (ComponentInstance) m_instances.get(i);
+ if (ci.getInstanceName().equals(name)) {
+ return ci;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Disposes the instance created with this component type which
+ * has the given name.
+ * @param name the name of the instance to delete.
+ * @return <code>true</code> is the instance is successfully disposed.
+ */
+ public boolean disposeInstance(String name) {
+ ComponentInstance ci = getInstanceByName(name);
+ if (ci == null) {
+ System.err.println("The instance was not found in this component type");
+ return false;
+ } else {
+ return disposeInstance(ci);
+ }
+ }
+
+ /**
+ * Returns the attached factory.
+ * Before returning the factory, the consistency of the
+ * factory is checked.
+ * @return the attached factory to the current component type
+ */
+ private Factory ensureAndGetFactory() {
+ ensureFactory();
+ return getFactory();
+ }
+
+ /**
+ * Checks if the factory is already created.
+ */
+ private void ensureFactory() {
+ if (getFactory() == null) {
+ throw new IllegalStateException("The factory associated with the component type is not created");
+ } else {
+ if (getFactory().getState() == Factory.INVALID) {
+ throw new IllegalStateException("The factory associated with the component type is invalid (not started or missing handlers)");
+ }
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
new file mode 100644
index 0000000..86366ba
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
@@ -0,0 +1,412 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows configuring a service dependencies.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Dependency implements HandlerConfiguration {
+
+ /**
+ * The dynamic binding policy.
+ */
+ public static final int DYNAMIC = org.apache.felix.ipojo.handlers.dependency.Dependency.DYNAMIC_BINDING_POLICY;
+
+ /**
+ * The static binding policy.
+ */
+ public static final int STATIC = org.apache.felix.ipojo.handlers.dependency.Dependency.STATIC_BINDING_POLICY;
+
+ /**
+ * The dynamic-priority binding policy.
+ */
+ public static final int DYNAMIC_PRIORITY = org.apache.felix.ipojo.handlers.dependency.Dependency.DYNAMIC_PRIORITY_BINDING_POLICY;
+
+ /**
+ * The required specification.
+ */
+ private String m_specification;
+
+ /**
+ * The LDAP filter of the dependency.
+ */
+ private String m_filter;
+
+ /**
+ * The field of the implementation class attached to
+ * this dependency.
+ */
+ private String m_field;
+
+ /**
+ * The constructor parameter index.
+ */
+ private int m_parameterIndex = -1;
+
+ /**
+ * Is the dependency optional?
+ */
+ private boolean m_optional;
+
+ /**
+ * Is the dependency aggregate?
+ */
+ private boolean m_aggregate;
+
+ /**
+ * Bind method attached to the dependency.
+ */
+ private String m_bind;
+
+ /**
+ * Unbind method attached to the dependency.
+ */
+ private String m_unbind;
+
+ /**
+ * Modified method attached to the dependency.
+ */
+ private String m_modified;
+
+ /**
+ * The dependency binding policy.
+ */
+ private int m_policy;
+
+ /**
+ * The dependency comparator.
+ * (used to compare service providers)
+ */
+ private String m_comparator;
+
+ /**
+ * The dependency default-implementation.
+ */
+ private String m_di;
+
+ /**
+ * The dependency specific provider.
+ */
+ private String m_from;
+
+ /**
+ * The dependency id.
+ */
+ private String m_id;
+
+ /**
+ * Does the dependency supports nullable?
+ */
+ private boolean m_nullable = true;
+
+ /**
+ * Does the dependency enables proxy.
+ */
+ private boolean m_proxy = true;
+
+ /**
+ * Gets the dependency metadata.
+ * @return the 'requires' element describing
+ * the current dependency.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("requires", "");
+ if (m_specification != null) {
+ dep.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_filter != null) {
+ dep.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_field != null) {
+ dep.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_parameterIndex != -1) {
+ dep.addAttribute(new Attribute("constructor-parameter",
+ Integer.toString(m_parameterIndex)));
+ }
+ if (m_bind != null) {
+ Element cb = new Element("callback", "");
+ cb.addAttribute(new Attribute("type", "bind"));
+ cb.addAttribute(new Attribute("method", m_bind));
+ dep.addElement(cb);
+ }
+ if (m_unbind != null) {
+ Element cb = new Element("callback", "");
+ cb.addAttribute(new Attribute("type", "unbind"));
+ cb.addAttribute(new Attribute("method", m_unbind));
+ dep.addElement(cb);
+ }
+ if (m_modified != null) {
+ Element cb = new Element("callback", "");
+ cb.addAttribute(new Attribute("type", "modified"));
+ cb.addAttribute(new Attribute("method", m_modified));
+ dep.addElement(cb);
+ }
+ if (m_comparator != null) {
+ dep.addAttribute(new Attribute("comparator", m_comparator));
+ }
+ if (m_di != null) {
+ dep.addAttribute(new Attribute("default-implementation", m_di));
+ }
+ if (m_from != null) {
+ dep.addAttribute(new Attribute("from", m_from));
+ }
+ if (m_id != null) {
+ dep.addAttribute(new Attribute("id", m_id));
+ }
+ if (! m_nullable) {
+ dep.addAttribute(new Attribute("nullable", "false"));
+ }
+ if (m_optional) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ if (m_aggregate) {
+ dep.addAttribute(new Attribute("aggregate", "true"));
+ }
+ if (! m_proxy) {
+ dep.addAttribute(new Attribute("proxy", "false"));
+ }
+ if (m_policy != -1) {
+ if (m_policy == DYNAMIC) {
+ dep.addAttribute(new Attribute("policy", "dynamic"));
+ } else if (m_policy == STATIC) {
+ dep.addAttribute(new Attribute("policy", "static"));
+ } else if (m_policy == DYNAMIC_PRIORITY) {
+ dep.addAttribute(new Attribute("policy", "dynamic-priority"));
+ }
+ // No other possibilities.
+ }
+ return dep;
+ }
+
+ /**
+ * Sets the required service specification.
+ * @param spec the specification
+ * @return the current dependency object.
+ */
+ public Dependency setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the LDAP filter
+ * @return the current dependency object
+ */
+ public Dependency setFilter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+ /**
+ * Sets the field attached to the dependency.
+ * @param field the implementation class field name.
+ * @return the current dependency object
+ */
+ public Dependency setField(String field) {
+ m_field = field;
+ return this;
+ }
+
+ /**
+ * Sets the constructor parameter index of the dependency.
+ * @param index the parameter index
+ * @return the current dependency object
+ */
+ public Dependency setConstructorParameter(int index) {
+ m_parameterIndex = index;
+ return this;
+ }
+
+ /**
+ * Sets the dependency optionality.
+ * @param opt <code>true</code> to set the
+ * dependency to optional.
+ * @return the current dependency object.
+ */
+ public Dependency setOptional(boolean opt) {
+ m_optional = opt;
+ return this;
+ }
+
+ /**
+ * Sets the dependency cardinality.
+ * @param agg <code>true</code> to set the
+ * dependency to aggregate.
+ * @return the current dependency object.
+ */
+ public Dependency setAggregate(boolean agg) {
+ m_aggregate = agg;
+ return this;
+ }
+
+ /**
+ * Sets if the dependency supports nullable objects.
+ * @param nullable <code>false</code> if the dependency does not
+ * support the nullable object injection
+ * @return the current dependency object.
+ */
+ public Dependency setNullable(boolean nullable) {
+ m_nullable = nullable;
+ return this;
+ }
+
+ /**
+ * Sets if the dependency injects proxies.
+ * @param proxy <code>false</code> if the dependency does not
+ * inject proxies but uses direct references.
+ * @return the current dependency object.
+ */
+ public Dependency setProxy(boolean proxy) {
+ m_proxy = proxy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency bind method.
+ * @param bind the bind method name
+ * @return the current dependency object.
+ */
+ public Dependency setBindMethod(String bind) {
+ m_bind = bind;
+ return this;
+ }
+
+ /**
+ * Sets the dependency unbind method.
+ * @param unbind the unbind method
+ * @return the current dependency object.
+ */
+ public Dependency setUnbindMethod(String unbind) {
+ m_unbind = unbind;
+ return this;
+ }
+
+ /**
+ * Sets the dependency modified method.
+ * @param modified the modified method
+ * @return the current dependency object.
+ */
+ public Dependency setModifiedMethod(String modified) {
+ m_modified = modified;
+ return this;
+ }
+
+ /**
+ * Sets the dependency binding policy.
+ * @param policy the binding policy
+ * @return the current dependency object
+ */
+ public Dependency setBindingPolicy(int policy) {
+ m_policy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency comparator.
+ * @param cmp the comparator class name
+ * @return the current dependency object
+ */
+ public Dependency setComparator(String cmp) {
+ m_comparator = cmp;
+ return this;
+ }
+
+ /**
+ * Sets the dependency default-implementation.
+ * @param di the default-implementation class name
+ * @return the current dependency object
+ */
+ public Dependency setDefaultImplementation(String di) {
+ m_di = di;
+ return this;
+ }
+
+ /**
+ * Sets the dependency 'from' attribute.
+ * @param from the name of the service provider.
+ * @return the current dependency object
+ */
+ public Dependency setFrom(String from) {
+ m_from = from;
+ return this;
+ }
+
+ /**
+ * Sets the dependency id.
+ * @param id the dependency id.
+ * @return the current dependency object.
+ */
+ public Dependency setId(String id) {
+ m_id = id;
+ return this;
+ }
+
+ /**
+ * Checks dependency configuration validity.
+ */
+ private void ensureValidity() {
+ // At least a field or methods.
+ if (m_field == null && m_bind == null && m_unbind == null && m_parameterIndex == -1) {
+ throw new IllegalStateException("A dependency must have a field or bind/unbind methods " +
+ "or a parameter index");
+ }
+ // Check binding policy.
+ if (m_policy != -1) {
+ if (!(m_policy == DYNAMIC || m_policy == STATIC || m_policy == DYNAMIC_PRIORITY)) {
+ throw new IllegalStateException("Unknow binding policy : " + m_policy);
+ }
+ }
+ }
+
+ /**
+ * Gets the dependency description object attached to
+ * this dependency.
+ * @param instance the instance on which searching the dependency
+ * @return the dependency description attached to this dependency or
+ * <code>null</code> if the dependency cannot be found.
+ */
+ public DependencyDescription getDependencyDescription(ComponentInstance instance) {
+ PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
+ if (m_id != null) {
+ return desc.getDependency(m_id);
+ }
+ if (m_specification != null) {
+ return desc.getDependency(m_specification);
+ }
+ DependencyDescription[] deps = desc.getDependencies();
+ if (deps.length == 1) {
+ return deps[0];
+ }
+ // Cannot determine the dependency.
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java
new file mode 100644
index 0000000..84f52b7
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Common interfaces for all contributions.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface HandlerConfiguration {
+
+ /**
+ * Gets the Handler description.
+ * @return the Element-Attribute structure containing the handler
+ * configuration.
+ */
+ Element getElement();
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
new file mode 100644
index 0000000..53a0931
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
@@ -0,0 +1,560 @@
+/*
+ * 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.api;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.manipulation.Manipulator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Allows defining primitive component types.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PrimitiveComponentType extends ComponentType {
+
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * The implementation class name.
+ */
+ private String m_classname;
+
+ /**
+ * The component type name.
+ */
+ private String m_name;
+
+ /**
+ * The component type version.
+ */
+ private String m_version;
+
+ /**
+ * Is the component type immediate.
+ */
+ private boolean m_immediate;
+
+ /**
+ * Manipulation metadata of the component type.
+ */
+ private Element m_manipulation;
+
+ /**
+ * Component factory attached to the component
+ * type.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * List of provided services.
+ */
+ private List<Service> m_services = new ArrayList<Service>(1);
+
+ /**
+ * List of service dependencies.
+ */
+ private List<Dependency> m_dependencies = new ArrayList<Dependency>();
+
+ /**
+ * List of configuration properties.
+ */
+ private List<Property> m_properties = new ArrayList<Property>();
+
+ /**
+ * The validate callback.
+ */
+ private String m_validate;
+
+ /**
+ * The invalidate callback.
+ */
+ private String m_invalidate;
+
+ /**
+ * The updated callback.
+ */
+ private String m_updated;
+
+ /**
+ * Are the properties propagated to provided services?
+ */
+ private boolean m_propagation;
+
+ /**
+ * The factory method.
+ */
+ private String m_factoryMethod;
+
+ /**
+ * Is the factory public?
+ */
+ private boolean m_public = true;
+
+ /**
+ * The Managed Service PID.
+ */
+ private String m_msPID;
+
+ /**
+ * The temporal dependencies.
+ */
+ private ArrayList<TemporalDependency> m_temporals = new ArrayList<TemporalDependency>();
+
+ /**
+ * List of Handler representing external
+ * handler configuration.
+ */
+ private List<HandlerConfiguration> m_handlers = new ArrayList<HandlerConfiguration>();
+
+
+ /**
+ * During the manipulation, we detect is the class is already manipulated.
+ * If set to <code>false</code>, the factory is configured to use the factory classloader.
+ */
+ private boolean m_alreadyManipulated = false;
+
+ /**
+ * Checks that the component type is not already
+ * started.
+ */
+ private void ensureNotInitialized() {
+ if (m_factory != null) {
+ throw new IllegalStateException("The component type was already initialized, cannot modify metadata");
+ }
+ }
+
+ /**
+ * Checks that the component type description is valid.
+ */
+ private void ensureValidity() {
+ if (m_classname == null) {
+ throw new IllegalStateException("The primitive component type has no implementation class");
+ }
+ if (m_context == null) {
+ throw new IllegalStateException("The primitive component type has no bundle context");
+ }
+ }
+
+ /**
+ * Gets the component factory.
+ * @return the factory attached to this component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#getFactory()
+ */
+ public Factory getFactory() {
+ initializeFactory();
+ return m_factory;
+ }
+
+ /**
+ * Starts the component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#start()
+ */
+ public void start() {
+ initializeFactory();
+ m_factory.start();
+ }
+
+ /**
+ * Stops the component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#stop()
+ */
+ public void stop() {
+ initializeFactory();
+ m_factory.stop();
+ }
+
+ /**
+ * Initializes the factory.
+ */
+ private void initializeFactory() {
+ if (m_factory == null) {
+ createFactory();
+ }
+ }
+
+ /**
+ * Sets the bundle context.
+ * @param bc the bundle context
+ * @return the current component type
+ */
+ public PrimitiveComponentType setBundleContext(BundleContext bc) {
+ ensureNotInitialized();
+ m_context = bc;
+ return this;
+ }
+
+ /**
+ * Sets the implementation class.
+ * @param classname the class name
+ * @return the current component type
+ */
+ public PrimitiveComponentType setClassName(String classname) {
+ ensureNotInitialized();
+ m_classname = classname;
+ return this;
+ }
+
+ /**
+ * Sets the component type name.
+ * @param name the factory name
+ * @return the current component type
+ */
+ public PrimitiveComponentType setComponentTypeName(String name) {
+ ensureNotInitialized();
+ m_name = name;
+ return this;
+ }
+
+ /**
+ * Sets the component type version.
+ * @param version the factory version or "bundle" to use the
+ * bundle version.
+ * @return the current component type
+ */
+ public PrimitiveComponentType setComponentTypeVersion(String version) {
+ ensureNotInitialized();
+ m_version = version;
+ return this;
+ }
+
+ /**
+ * Sets if the component type is immediate or not.
+ * @param immediate <code>true</code> to set the component
+ * type to immediate
+ * @return the current component type
+ */
+ public PrimitiveComponentType setImmediate(boolean immediate) {
+ ensureNotInitialized();
+ m_immediate = immediate;
+ return this;
+ }
+
+ /**
+ * Sets the dependency factory method.
+ * @param method the method used to create pojo object.
+ * @return the current component type
+ */
+ public PrimitiveComponentType setFactoryMethod(String method) {
+ ensureNotInitialized();
+ m_factoryMethod = method;
+ return this;
+ }
+
+ /**
+ * Sets if the component type propagates properties to service properties.
+ * @param propagation <code>true</code> to enable propagation
+ * @return the current component type
+ */
+ public PrimitiveComponentType setPropagation(boolean propagation) {
+ ensureNotInitialized();
+ m_propagation = propagation;
+ return this;
+ }
+
+ /**
+ * Sets the factory public aspect.
+ * @param visible <code>false</code> to create a private factory.
+ * @return the current component type
+ */
+ public PrimitiveComponentType setPublic(boolean visible) {
+ ensureNotInitialized();
+ m_public = visible;
+ return this;
+ }
+
+ /**
+ * Sets the managed service pid.
+ * @param pid the managed service pid
+ * @return the current component type
+ */
+ public PrimitiveComponentType setManagedServicePID(String pid) {
+ ensureNotInitialized();
+ m_msPID = pid;
+ return this;
+ }
+
+ /**
+ * Sets the validate method.
+ * @param method the validate method
+ * @return the current component type
+ */
+ public PrimitiveComponentType setValidateMethod(String method) {
+ ensureNotInitialized();
+ m_validate = method;
+ return this;
+ }
+
+ /**
+ * Sets the invalidate method.
+ * @param method the invalidate method
+ * @return the current component type
+ */
+ public PrimitiveComponentType setInvalidateMethod(String method) {
+ ensureNotInitialized();
+ m_invalidate = method;
+ return this;
+ }
+
+ /**
+ * Sets the updated method.
+ * @param method the updated method
+ * @return the current component type
+ */
+ public PrimitiveComponentType setUpdatedMethod(String method) {
+ ensureNotInitialized();
+ m_updated = method;
+ return this;
+ }
+
+ /**
+ * Generates the component description.
+ * @return the component type description of
+ * the current component type
+ */
+ private Element generateComponentMetadata() {
+ Element element = new Element("component", "");
+ element.addAttribute(new Attribute("classname", m_classname));
+ if (m_name != null) {
+ element.addAttribute(new Attribute("name", m_name));
+ }
+ if (m_version != null) {
+ element.addAttribute(new Attribute("version", m_version));
+ }
+ if (m_factoryMethod != null) {
+ element.addAttribute(new Attribute("factory-method", m_factoryMethod));
+ }
+ if (! m_public) {
+ element.addAttribute(new Attribute("public", "false"));
+ }
+ if (m_immediate) {
+ element.addAttribute(new Attribute("immediate", "true"));
+ }
+ for (Service svc : m_services) {
+ element.addElement(svc.getElement());
+ }
+ for (Dependency dep : m_dependencies) {
+ element.addElement(dep.getElement());
+ }
+ for (TemporalDependency dep : m_temporals) {
+ element.addElement(dep.getElement());
+ }
+ if (m_validate != null) {
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("transition", "validate"));
+ callback.addAttribute(new Attribute("method", m_validate));
+ element.addElement(callback);
+ }
+ if (m_invalidate != null) {
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("transition", "invalidate"));
+ callback.addAttribute(new Attribute("method", m_invalidate));
+ element.addElement(callback);
+ }
+
+ // Properties
+ // First determine if we need the properties element
+ if (m_propagation || m_msPID != null || ! m_properties.isEmpty()) {
+ Element properties = new Element("properties", "");
+ if (m_propagation) {
+ properties.addAttribute(new Attribute("propagation", "true"));
+ }
+ if (m_msPID != null) {
+ properties.addAttribute(new Attribute("pid", m_msPID));
+ }
+ if (m_updated != null) {
+ properties.addAttribute(new Attribute("updated", m_updated));
+ }
+ for (Property prop : m_properties) {
+ properties.addElement(prop.getElement());
+ }
+ element.addElement(properties);
+ }
+
+ // External handlers
+ for (HandlerConfiguration hc : m_handlers) {
+ element.addElement(hc.getElement());
+ }
+
+ return element;
+ }
+
+
+ /**
+ * Adds an HandlerConfiguration to the component type. Each component type
+ * implementation must uses the populated list (m_handlers) when generating
+ * the component metadata.
+ * @param handler the handler configuration to add
+ * @return the current component type
+ */
+ public PrimitiveComponentType addHandler(HandlerConfiguration handler) {
+ m_handlers.add(handler);
+ return this;
+ }
+
+ /**
+ * Creates the component factory.
+ */
+ private void createFactory() {
+ ensureValidity();
+ byte[] clazz = manipulate();
+
+ Element meta = generateComponentMetadata();
+ meta.addElement(m_manipulation);
+ try {
+ if (m_alreadyManipulated) { // Already manipulated
+ m_factory = new ComponentFactory(m_context, meta);
+ } else {
+ m_factory = new ComponentFactory(m_context, clazz, meta);
+ m_factory.setUseFactoryClassloader(true);
+ }
+ m_factory.start();
+ } catch (ConfigurationException e) {
+ throw new IllegalStateException("An exception occurs during factory initialization", e);
+ }
+
+ }
+
+ /**
+ * Manipulates the implementation class.
+ * @return the manipulated class
+ */
+ private byte[] manipulate() {
+ Manipulator manipulator = new Manipulator(new ClassLoader() {
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ try {
+ return m_context.getBundle().loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return this.getClass().getClassLoader().loadClass(name);
+ }
+ }
+ });
+ try {
+ byte[] array = getClassByteArray();
+
+ // Step 1 - preparation
+ manipulator.prepare(array);
+
+ byte[] newclazz = new byte[0];
+ if (!manipulator.isAlreadyManipulated()) {
+ // Step 2 - manipulation
+ newclazz = manipulator.manipulate(array);
+ }
+ m_manipulation = manipulator.getManipulationMetadata();
+ m_alreadyManipulated = manipulator.isAlreadyManipulated();
+ return newclazz;
+ } catch (IOException e) {
+ throw new IllegalStateException("An exception occurs during implementation class manipulation", e);
+ }
+ }
+
+ /**
+ * Gets a class file as a byte array.
+ * @return the byte array.
+ * @throws IOException the class file cannot be read.
+ */
+ private byte[] getClassByteArray() throws IOException {
+ String filename = m_classname.replace('.', '/') + ".class";
+ URL url = m_context.getBundle().getResource(filename);
+ if (url == null) {
+ throw new IllegalStateException("An exception occurs during implementation class manipulation : cannot found the class file " + filename);
+ }
+ InputStream is = url.openStream();
+ if (is == null) {
+ throw new IllegalStateException("An exception occurs during implementation class manipulation : cannot read the class file " + url);
+ }
+ byte[] b = new byte[is.available()];
+ is.read(b);
+ return b;
+ }
+
+ /**
+ * Adds a provided service.
+ * @param svc the service to add
+ * @return the current component type
+ */
+ public PrimitiveComponentType addService(Service svc) {
+ ensureNotInitialized();
+ m_services.add(svc);
+ return this;
+ }
+
+ /**
+ * Adds a service dependency.
+ * @param dep the dependency to add
+ * @return the current component type
+ */
+ public PrimitiveComponentType addDependency(Dependency dep) {
+ ensureNotInitialized();
+ m_dependencies.add(dep);
+ return this;
+ }
+
+ /**
+ * Adds a temporal service dependency.
+ * @param dep the temporal dependency to add
+ * @return the current component type
+ */
+ public PrimitiveComponentType addDependency(TemporalDependency dep) {
+ ensureNotInitialized();
+ m_temporals.add(dep);
+ return this;
+ }
+
+ /**
+ * Adds a configuration property.
+ * @param prop the property to add
+ * @return the current component type
+ */
+ public PrimitiveComponentType addProperty(Property prop) {
+ ensureNotInitialized();
+ m_properties.add(prop);
+ return this;
+ }
+
+ /**
+ * Adds a configuration property.
+ * @param key the key
+ * @param obj the value (can be <code>null</code>)
+ * @return the current component type
+ */
+ public PrimitiveComponentType addProperty(String key, Object obj) {
+ String value = null;
+ if (obj != null) {
+ value = obj.toString();
+ }
+
+ addProperty(new Property().setName(key).setValue(value));
+ return this;
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Property.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Property.java
new file mode 100644
index 0000000..9387941
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Property.java
@@ -0,0 +1,205 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows configuring a configuration property.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Property {
+
+ /**
+ * The property name.
+ */
+ private String m_name;
+
+ /**
+ * The property field.
+ */
+ private String m_field;
+
+ /**
+ * The constructor parameter index.
+ */
+ private int m_parameterIndex = -1;
+
+ /**
+ * The property value.
+ */
+ private String m_value;
+
+ /**
+ * The property method.
+ */
+ private String m_method;
+
+ /**
+ * Is the property mandatory.
+ */
+ private boolean m_mandatory;
+
+ /**
+ * Is the property immutable.
+ */
+ private boolean m_immutable;
+
+ /**
+ * Sets the property name.
+ * @param name the property name
+ * @return the current property object
+ */
+ public Property setName(String name) {
+ m_name = name;
+ return this;
+ }
+
+ /**
+ * Sets the property field.
+ * @param name the property field
+ * @return the current property object
+ */
+ public Property setField(String name) {
+ m_field = name;
+ return this;
+ }
+
+ /**
+ * Sets the constructor parameter index of the property.
+ * @param index the parameter index
+ * @return the current property object
+ */
+ public Property setConstructorParameter(int index) {
+ m_parameterIndex = index;
+ return this;
+ }
+
+ /**
+ * Sets the property method.
+ * @param name the property method
+ * @return the current property object
+ */
+ public Property setMethod(String name) {
+ m_method = name;
+ return this;
+ }
+
+ /**
+ * Sets the property value.
+ * @param name the property value
+ * @return the current property object
+ */
+ public Property setValue(String name) {
+ m_value = name;
+ return this;
+ }
+
+ /**
+ * Sets if the property is mandatory.
+ * @param mandatory <code>true</code> if the dependency is mandatory.
+ * @return the current property object
+ */
+ public Property setMandatory(boolean mandatory) {
+ m_mandatory = mandatory;
+ return this;
+ }
+
+ /**
+ * Sets if the property is immutable.
+ * @param immutable <code>true</code> if the dependency is immutable.
+ * @return the current property object
+ */
+ public Property setImmutable(boolean immutable) {
+ m_immutable = immutable;
+ return this;
+ }
+
+ /**
+ * Gets the property element.
+ * @return the property element.
+ */
+ public Element getElement() {
+ ensureValidity();
+ Element element = new Element("property", "");
+ if (m_name != null) {
+ element.addAttribute(new Attribute("name", m_name));
+ }
+ if (m_method != null) {
+ element.addAttribute(new Attribute("method", m_method));
+ }
+ if (m_parameterIndex != -1) {
+ element.addAttribute(new Attribute("constructor-parameter",
+ Integer.toString(m_parameterIndex)));
+ }
+ if (m_value != null) {
+ element.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_field != null) {
+ element.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_mandatory) {
+ element.addAttribute(new Attribute("mandatory", new Boolean(m_mandatory).toString()));
+ }
+ if (m_immutable) {
+ element.addAttribute(new Attribute("immutable", new Boolean(m_immutable).toString()));
+ }
+ return element;
+ }
+
+ /**
+ * Checks the configuration validity.
+ */
+ private void ensureValidity() {
+ // Two cases
+ // Field or Method
+ if (m_field == null && m_method == null && m_parameterIndex == -1) {
+ throw new IllegalStateException("A property must have either a field or a method " +
+ "or a constructor parameter");
+ }
+ if (m_immutable && m_value == null) {
+ throw new IllegalStateException("A immutable service property must have a value");
+ }
+ }
+
+ /**
+ * Gets the property description for the current property.
+ * @param instance the component instance on which looking for the property.
+ * @return the property description associated with the current property
+ * or <code>null</code> if not found.
+ */
+ public PropertyDescription getPropertyDescription(ComponentInstance instance) {
+ PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
+ PropertyDescription[] props = desc.getProperties();
+
+ for (int i = 0; i < props.length; i++) {
+ if ((m_name != null && m_name.equals(props[i].getName()))
+ || (m_field != null && m_field.equals(props[i].getName()))) {
+ return props[i];
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Service.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Service.java
new file mode 100644
index 0000000..99499ef
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/Service.java
@@ -0,0 +1,320 @@
+/*
+ * 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.api;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows configuring a provided service.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Service implements HandlerConfiguration {
+
+ /**
+ * Creation strategy : singleton (default).
+ */
+ public static final int SINGLETON_STRATEGY = ProvidedService.SINGLETON_STRATEGY;
+
+ /**
+ * Creation strategy : delegate on the static factory method.
+ */
+ public static final int STATIC_STRATEGY = ProvidedService.STATIC_STRATEGY;
+
+ /**
+ * Creation strategy : one service object per instance.
+ */
+ public static final int INSTANCE_STRATEGY = ProvidedService.INSTANCE_STRATEGY;
+
+ /**
+ * Creation strategy : one service object per bundle (OSGi service factory).
+ */
+ public static final int SERVICE_STRATEGY = ProvidedService.SERVICE_STRATEGY;
+
+ /**
+ * The provided service specification.
+ */
+ private List m_specifications; // null be default computed.
+
+ /**
+ * The provided service strategy.
+ */
+ private int m_strategy = ProvidedService.SINGLETON_STRATEGY;
+
+ /**
+ * The provided service custom strategy.
+ */
+ private String m_customStrategy;
+
+ /**
+ * The service properties.
+ */
+ private List m_properties = new ArrayList();
+
+ /**
+ * Service controller.
+ */
+ private String m_controller;
+
+ /**
+ * Service Controller value.
+ */
+ private boolean m_controllerValue;
+
+ /**
+ * Post-Registration callback.
+ */
+ private String m_postRegistrationCallback;
+
+ /**
+ * Post-Unregistration callback.
+ */
+ private String m_postUnregistrationCallback;
+
+ /**
+ * Gets the provided service element.
+ * @return the 'provides' element.
+ */
+ public Element getElement() {
+ ensureValidity();
+ Element element = new Element("provides", "");
+ if (m_specifications != null) {
+ element.addAttribute(new Attribute("specifications", getSpecificationsArray()));
+ }
+ element.addAttribute(new Attribute("strategy", getStringStrategy()));
+ for (int i = 0; i < m_properties.size(); i++) {
+ element.addElement(((ServiceProperty) m_properties.get(i)).getElement());
+ }
+
+ if (m_controller != null) {
+ Element ctrl = new Element("controller", "");
+ ctrl.addAttribute(new Attribute("field", m_controller));
+ ctrl.addAttribute(new Attribute("value", String.valueOf(m_controllerValue)));
+ element.addElement(ctrl);
+ }
+
+ if (m_postRegistrationCallback != null) {
+ element.addAttribute(new Attribute("post-registration", m_postRegistrationCallback));
+ }
+ if (m_postUnregistrationCallback != null) {
+ element.addAttribute(new Attribute("post-unregistration", m_postUnregistrationCallback));
+ }
+
+ return element;
+ }
+
+ /**
+ * Gets the provided service description associated with the current service.
+ * @param instance the instance on which looking for the provided service description
+ * @return the provided service description or <code>null</code> if not found.
+ */
+ public ProvidedServiceDescription getProvidedServiceDescription(ComponentInstance instance) {
+ PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
+ ProvidedServiceDescription[] pss = desc.getProvidedServices();
+ if (pss.length == 0) {
+ return null;
+ }
+
+ if (pss.length == 1) {
+ return pss[0];
+ }
+
+ if (m_specifications == null) {
+ return null;
+ } else {
+ for (int j = 0; j < pss.length; j++) {
+ ProvidedServiceDescription psd = pss[j];
+ List specs = Arrays.asList(psd.getServiceSpecifications());
+ if (specs.containsAll(m_specifications)) {
+ return psd;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+
+ /**
+ * Checks the validity of the configuration.
+ */
+ private void ensureValidity() {
+ // No check required.
+ }
+
+
+ /**
+ * The the service specification array as a String.
+ * @return the string-from of the service specifications.
+ */
+ private String getSpecificationsArray() {
+ if (m_specifications.size() == 1) {
+ return (String) m_specifications.get(0);
+ } else {
+ StringBuffer buffer = new StringBuffer("{");
+ for (int i = 0; i < m_specifications.size(); i++) {
+ if (i != 0) {
+ buffer.append(',');
+ }
+ buffer.append(m_specifications.get(i));
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Adds a service property.
+ * @param ps the service property to add
+ * @return the current service object.
+ */
+ public Service addProperty(ServiceProperty ps) {
+ m_properties.add(ps);
+ return this;
+ }
+
+ /**
+ * Adds a service property.
+ * @param key the property key
+ * @param obj the initial value (can be <code>null</code>)
+ * @return the current service object.
+ */
+ public Service addProperty(String key, Object obj) {
+ Class clazz = String.class;
+ String value = null;
+ if (obj != null) {
+ clazz = obj.getClass();
+ value = obj.toString();
+ }
+
+ addProperty(new ServiceProperty().setName(key).setType(clazz.getName())
+ .setValue(value));
+
+ return this;
+ }
+
+ /**
+ * Sets the provided service specification.
+ * @param spec the service specification
+ * @return the current service object.
+ */
+ public Service setSpecification(String spec) {
+ m_specifications = new ArrayList(1);
+ m_specifications.add(spec);
+ return this;
+ }
+
+ /**
+ * Sets the provided service specifications.
+ * @param specs the service specifications
+ * @return the current service object.
+ */
+ public Service setSpecifications(List specs) {
+ m_specifications = specs;
+ return this;
+ }
+
+ /**
+ * Sets the creation strategy.
+ * @param strategy the service strategy.
+ * @return the current service object
+ */
+ public Service setCreationStrategy(int strategy) {
+ m_strategy = strategy;
+ return this;
+ }
+
+ /**
+ * Sets the creation strategy.
+ * This method allows using a customized
+ * service strategy.
+ * @param strategy the service strategy
+ * @return the current service object
+ */
+ public Service setCreationStrategy(String strategy) {
+ m_strategy = -1; // Custom
+ m_customStrategy = strategy;
+ return this;
+ }
+
+ /**
+ * Sets the service controller.
+ * @param field the controller field
+ * @param initialValue the initial value
+ * @return the current service object
+ */
+ public Service setServiceController(String field,
+ boolean initialValue) {
+ m_controller = field;
+ m_controllerValue = initialValue;
+ return this;
+ }
+
+ /**
+ * Sets the post-registration callback.
+ * @param callback the callback name (method name)
+ * @return the current service object
+ */
+ public Service setPostRegistrationCallback(String callback) {
+ m_postRegistrationCallback = callback;
+ return this;
+ }
+
+ /**
+ * Sets the post-unregistration callback.
+ * @param callback the callback name (method name)
+ * @return the current service object
+ */
+ public Service setPostUnregistrationCallback(String callback) {
+ m_postUnregistrationCallback = callback;
+ return this;
+ }
+
+ /**
+ * Gets the string-form of the creation strategy.
+ * @return the creation strategy string form
+ */
+ private String getStringStrategy() {
+ switch (m_strategy) {
+ case -1: // Custom policies
+ return m_customStrategy;
+ case ProvidedService.SINGLETON_STRATEGY:
+ return "singleton";
+ case ProvidedService.STATIC_STRATEGY:
+ return "method";
+ case ProvidedService.SERVICE_STRATEGY:
+ return "service";
+ case ProvidedService.INSTANCE_STRATEGY:
+ return "instance";
+ default:
+ throw new IllegalStateException("Unknown creation strategy : "
+ + m_strategy);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ServiceProperty.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ServiceProperty.java
new file mode 100644
index 0000000..eb2d93b
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/ServiceProperty.java
@@ -0,0 +1,192 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows configuring a service property.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceProperty {
+
+ /**
+ * The property name.
+ */
+ private String m_name;
+
+ /**
+ * The property field.
+ */
+ private String m_field;
+
+ /**
+ * The property type.
+ */
+ private String m_type;
+
+ /**
+ * The property value.
+ */
+ private String m_value;
+
+ /**
+ * Is the property mandatory.
+ */
+ private boolean m_mandatory;
+
+ /**
+ * Is the property immutable.
+ */
+ private boolean m_immutable;
+
+ /**
+ * Sets the property name.
+ * @param name the property name
+ * @return the current property object
+ */
+ public ServiceProperty setName(String name) {
+ m_name = name;
+ return this;
+ }
+
+ /**
+ * Sets the property field.
+ * @param name the property field
+ * @return the current property object
+ */
+ public ServiceProperty setField(String name) {
+ m_field = name;
+ return this;
+ }
+
+ /**
+ * Sets the property type.
+ * @param name the property type
+ * @return the current property object
+ */
+ public ServiceProperty setType(String name) {
+ m_type = name;
+ return this;
+ }
+
+ /**
+ * Sets the property value.
+ * @param name the property value
+ * @return the current property object
+ */
+ public ServiceProperty setValue(String name) {
+ m_value = name;
+ return this;
+ }
+
+ /**
+ * Sets if the property is immutable.
+ * @param immutable <code>true</code> if the dependency is immutable.
+ * @return the current property object
+ */
+ public ServiceProperty setImmutable(boolean immutable) {
+ m_immutable = immutable;
+ return this;
+ }
+
+ /**
+ * Sets if the property is mandatory.
+ * @param mandatory <code>true</code> if the dependency is mandatory.
+ * @return the current property object
+ */
+ public ServiceProperty setMandatory(boolean mandatory) {
+ m_mandatory = mandatory;
+ return this;
+ }
+
+
+ /**
+ * Gets the 'property' element.
+ * @return the element describing the current property.
+ */
+ public Element getElement() {
+ ensureValidity();
+ Element element = new Element("property", "");
+ if (m_name != null) {
+ element.addAttribute(new Attribute("name", m_name));
+ }
+ if (m_type != null) {
+ element.addAttribute(new Attribute("type", m_type));
+ }
+ if (m_value != null) {
+ element.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_field != null) {
+ element.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_mandatory) {
+ element.addAttribute(new Attribute("mandatory", new Boolean(m_mandatory).toString()));
+ }
+ if (m_immutable) {
+ element.addAttribute(new Attribute("immutable", new Boolean(m_immutable).toString()));
+ }
+ return element;
+ }
+
+ /**
+ * Checks the configuration validity.
+ */
+ private void ensureValidity() {
+ // Two cases
+ // Field or type
+ if (m_field == null && m_type == null) {
+ throw new IllegalStateException("A service property must have either a field or a type");
+ }
+ if (m_immutable && m_value == null) {
+ throw new IllegalStateException("A immutable service property must have a value");
+ }
+ }
+
+ /**
+ * Gets the property value of the current property
+ * on the given instance.
+ * @param instance the instance on which looking for
+ * the property value
+ * @return the property value or <code>null</code>
+ * if not found.
+ */
+ public Object getPropertyValue(ComponentInstance instance) {
+ PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
+ ProvidedServiceDescription[] pss = desc.getProvidedServices();
+ for (int i = 0; i < pss.length; i++) {
+ // Check with the name
+ if (m_name != null && pss[i].getProperties().containsKey(m_name)) {
+ return pss[i].getProperties().get(m_name);
+ }
+ // Check with the field
+ if (m_field != null && pss[i].getProperties().containsKey(m_field)) {
+ return pss[i].getProperties().get(m_field);
+ }
+ }
+ // Not found.
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/SingletonComponentType.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/SingletonComponentType.java
new file mode 100644
index 0000000..39f510d
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/SingletonComponentType.java
@@ -0,0 +1,140 @@
+/*
+ * 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.api;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+
+/**
+ * Allows defining a primitive component type that create an unique
+ * instance when created. The factory is set to private by default.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SingletonComponentType extends PrimitiveComponentType {
+
+ /**
+ * The POJO object to inject through the
+ * instance configuration.
+ */
+ private Object m_pojo;
+
+ /**
+ * Creates a SingletonComponentType.
+ * This type is set to private by default.
+ */
+ public SingletonComponentType() {
+ setPublic(false);
+ }
+
+ /**
+ * Sets the pojo object used by the instance.
+ * The object must be compatible with the
+ * implementation class.
+ * @param obj the object.
+ * @return the current singleton component type.
+ */
+ public SingletonComponentType setObject(Object obj) {
+ m_pojo = obj;
+ return this;
+ }
+
+ /**
+ * Starts the component type and creates the singleton
+ * instance. This method has to be called in place of the
+ * {@link PrimitiveComponentType#start()} and the
+ * {@link PrimitiveComponentType#createInstance()} methods.
+ * @return the created component instance.
+ * @throws ConfigurationException occurs if the type description is
+ * incorrect
+ * @throws MissingHandlerException occurs if a handler is not available
+ * @throws UnacceptableConfiguration occurs if the configuration is not
+ * acceptable by the instance
+ * @see org.apache.felix.ipojo.api.ComponentType#start()
+ * @see PrimitiveComponentType#createInstance()
+ */
+ public ComponentInstance create() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ start();
+ if (m_pojo != null) {
+ Dictionary dict = new Properties();
+ dict.put("instance.object", m_pojo);
+ return createInstance(dict);
+ } else {
+ return createInstance();
+ }
+ }
+
+ /**
+ * Starts the component type and creates the singleton
+ * instance. This method has to be called in place of the
+ * {@link PrimitiveComponentType#start()} and the
+ * {@link PrimitiveComponentType#createInstance()} methods.
+ * @param conf the instance configuration
+ * @return the created component instance
+ * @throws ConfigurationException occurs if the type description is
+ * incorrect
+ * @throws MissingHandlerException occurs if a handler is not available
+ * @throws UnacceptableConfiguration occurs if the configuration is not
+ * acceptable by the instance
+ * @see org.apache.felix.ipojo.api.ComponentType#start()
+ * @see PrimitiveComponentType#createInstance()
+ */
+ public ComponentInstance create(Dictionary conf) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ start();
+ if (m_pojo != null) {
+ conf.put("instance.object", m_pojo);
+ }
+ return createInstance(conf);
+ }
+
+ /**
+ * Starts the component type and creates the singleton
+ * instance. This method has to be called in place of the
+ * {@link PrimitiveComponentType#start()} and the
+ * {@link PrimitiveComponentType#createInstance()} methods.
+ * @param name the name of the instance to create. This parameter will
+ * be used as the <code>instance.name</code> property.
+ * @return the created component instance.
+ * @throws ConfigurationException occurs if the type description is
+ * incorrect
+ * @throws MissingHandlerException occurs if a handler is not available
+ * @throws UnacceptableConfiguration occurs if the configuration is not
+ * acceptable by the instance
+ * @see org.apache.felix.ipojo.api.ComponentType#start()
+ * @see PrimitiveComponentType#createInstance()
+ */
+ public ComponentInstance create(String name) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ start();
+ if (m_pojo != null) {
+ Dictionary dict = new Properties();
+ dict.put("instance.name", name);
+ dict.put("instance.object", m_pojo);
+ return createInstance(dict);
+ } else {
+ return createInstance(name);
+ }
+ }
+
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java
new file mode 100644
index 0000000..713bf0a
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java
@@ -0,0 +1,195 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows configuring a service dependencies.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TemporalDependency implements HandlerConfiguration {
+
+ /**
+ * OnTimeout policy: nullable object.
+ */
+ public static final String NULLABLE = "nullable";
+
+ /**
+ * OnTimeout policy: empty array or collection.
+ */
+ public static final String EMPTY = "empty";
+
+ /**
+ * OnTimeout policy: inject null.
+ */
+ public static final String NULL = "null";
+
+
+ /**
+ * The required specification.
+ */
+ private String m_specification;
+
+ /**
+ * The LDAP filter of the dependency.
+ */
+ private String m_filter;
+
+ /**
+ * The field of the implementation class attached to
+ * this dependency.
+ */
+ private String m_field;
+
+ /**
+ * OnTimeout policy.
+ */
+ private String m_onTimeout;
+
+ /**
+ * Timeout.
+ */
+ private String m_timeout;
+
+ /**
+ * Proxy.
+ */
+ private boolean m_proxy = false;
+
+ /**
+ * Gets the dependency metadata.
+ * @return the 'requires' element describing
+ * the current dependency.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("requires", "org.apache.felix.ipojo.handler.temporal");
+ if (m_specification != null) {
+ dep.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_filter != null) {
+ dep.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_field != null) {
+ dep.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_onTimeout != null) {
+ dep.addAttribute(new Attribute("omTimeout", m_onTimeout));
+ }
+ if (m_timeout != null) {
+ dep.addAttribute(new Attribute("timeout", m_timeout));
+ }
+ if (m_proxy) {
+ dep.addAttribute(new Attribute("proxy", "true"));
+ }
+
+ return dep;
+ }
+
+ /**
+ * Sets the required service specification.
+ * @param spec the specification
+ * @return the current dependency object.
+ */
+ public TemporalDependency setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the LDAP filter
+ * @return the current dependency object
+ */
+ public TemporalDependency setFilter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+ /**
+ * Sets the field attached to the dependency.
+ * @param field the implementation class field name.
+ * @return the current dependency object
+ */
+ public TemporalDependency setField(String field) {
+ m_field = field;
+ return this;
+ }
+
+ /**
+ * Sets if the dependency is injected as a proxy.
+ * @param proxy <code>true</code> to inject proxies.
+ * @return the current dependency object.
+ */
+ public TemporalDependency setProxy(boolean proxy) {
+ m_proxy = proxy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency timeout.
+ * @param time the dependency timeout in ms
+ * 'infinite' for infinite.
+ * @return the current dependency object
+ */
+ public TemporalDependency setTimeout(String time) {
+ m_timeout = time;
+ return this;
+ }
+
+ /**
+ * Sets the dependency timeout.
+ * @param time the dependency timeout in ms
+ * @return the current dependency object
+ */
+ public TemporalDependency setTimeout(long time) {
+ m_timeout = new Long(time).toString();
+ return this;
+ }
+
+ /**
+ * Sets the dependency ontimeout policy.
+ * Supports null, nullable, empty, and default-implementation.
+ * In this latter case, you must specify the qualified class name
+ * of the default-implementation (instead of default-implementation).
+ * Default: no action (i.e throws a runtime exception)
+ * @param tip the ontimeout policy
+ * @return the current dependency object
+ */
+ public TemporalDependency setOnTimeoutPolicy(String tip) {
+ m_onTimeout = tip;
+ return this;
+ }
+
+
+ /**
+ * Checks dependency configuration validity.
+ */
+ private void ensureValidity() {
+ // At least a field or methods.
+ if (m_field == null) {
+ throw new IllegalStateException("A temporal dependency must have a field");
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
new file mode 100644
index 0000000..9fc3f26
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
@@ -0,0 +1,329 @@
+/*
+ * 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.api.composite;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.api.ComponentType;
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.composite.CompositeFactory;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Allows defining composite types.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeComponentType extends ComponentType {
+
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Component factory attached to the component
+ * type.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Component type metadata.
+ */
+ private Element m_metadata;
+
+ /**
+ * List of provided services.
+ */
+ private List m_provided = new ArrayList(1);
+
+ /**
+ * List of exported services.
+ */
+ private List m_exported = new ArrayList(1);
+
+ /**
+ * List of imported services.
+ */
+ private List m_imported = new ArrayList(1);
+
+ /**
+ * List of instantiated services.
+ */
+ private List m_instantiated = new ArrayList();
+
+ /**
+ * List of contained instance.
+ */
+ private List m_contained = new ArrayList();
+
+ /**
+ * Is the factory public?
+ */
+ private boolean m_public = true;
+
+ /**
+ * Component type name.
+ */
+ private String m_name;
+
+ /**
+ * Component type version.
+ */
+ private String m_version;
+
+ /**
+ * List of Handler representing external.
+ * handler configuration
+ */
+ private List m_handlers = new ArrayList();
+
+ /**
+ * Checks that the component type is not already
+ * started.
+ */
+ private void ensureNotInitialized() {
+ if (m_factory != null) {
+ throw new IllegalStateException("The component type was already initialized, cannot modify metadata");
+ }
+ }
+
+ /**
+ * Checks that the component type description is valid.
+ */
+ private void ensureValidity() {
+ if (m_context == null) {
+ throw new IllegalStateException("The composite component type has no bundle context");
+ }
+ }
+
+ /**
+ * Gets the component factory.
+ * @return the factory attached to this component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#getFactory()
+ */
+ public Factory getFactory() {
+ initializeFactory();
+ return m_factory;
+ }
+
+ /**
+ * Starts the component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#start()
+ */
+ public void start() {
+ initializeFactory();
+ m_factory.start();
+ }
+
+ /**
+ * Stops the component type.
+ * @see org.apache.felix.ipojo.api.ComponentType#stop()
+ */
+ public void stop() {
+ initializeFactory();
+ m_factory.stop();
+ }
+
+ /**
+ * Initializes the factory.
+ */
+ private void initializeFactory() {
+ if (m_factory == null) {
+ createFactory();
+ }
+ }
+
+ /**
+ * Sets the bundle context.
+ * @param bc the bundle context
+ * @return the current component type
+ */
+ public CompositeComponentType setBundleContext(BundleContext bc) {
+ ensureNotInitialized();
+ m_context = bc;
+ return this;
+ }
+
+ /**
+ * Sets the factory public aspect.
+ * @param visible <code>false</code> to create a private factory.
+ * @return the current component type
+ */
+ public CompositeComponentType setPublic(boolean visible) {
+ ensureNotInitialized();
+ m_public = visible;
+ return this;
+ }
+
+ /**
+ * Sets the component type name.
+ * @param name the factory name
+ * @return the current component type
+ */
+ public CompositeComponentType setComponentTypeName(String name) {
+ ensureNotInitialized();
+ m_name = name;
+ return this;
+ }
+
+ /**
+ * Sets the component type version.
+ * @param version the factory version or "bundle" to use the
+ * bundle version.
+ * @return the current component type
+ */
+ public CompositeComponentType setComponentTypeVersion(String version) {
+ ensureNotInitialized();
+ m_version = version;
+ return this;
+ }
+
+ /**
+ * Adds a contained instance.
+ * @param inst the instance to add
+ * @return the current composite component type
+ */
+ public CompositeComponentType addInstance(Instance inst) {
+ m_contained.add(inst);
+ return this;
+ }
+
+ /**
+ * Adds an imported (sub-)service.
+ * @param is the imported service to add
+ * @return the current composite component type
+ */
+ public CompositeComponentType addSubService(ImportedService is) {
+ m_imported.add(is);
+ return this;
+ }
+
+ /**
+ * Adds an instantiated sub-service.
+ * @param is the instantiated service to add
+ * @return the current composite component type
+ */
+ public CompositeComponentType addSubService(InstantiatedService is) {
+ m_instantiated.add(is);
+ return this;
+ }
+
+ /**
+ * Adds an exported service.
+ * @param es the exported service to add
+ * @return the current composite component type
+ */
+ public CompositeComponentType addService(ExportedService es) {
+ m_exported.add(es);
+ return this;
+ }
+
+ /**
+ * Adds a provided service.
+ * @param es the provided service to add
+ * @return the current composite component type
+ */
+ public CompositeComponentType addService(ProvidedService es) {
+ m_provided.add(es);
+ return this;
+ }
+
+ /**
+ * Adds an HandlerConfiguration to the component type. Each component type
+ * implementation must uses the populated list (m_handlers) when generating
+ * the component metadata.
+ * @param handler the handler configuration to add
+ * @return the current component type.
+ */
+ public CompositeComponentType addHandler(HandlerConfiguration handler) {
+ m_handlers.add(handler);
+ return this;
+ }
+
+ /**
+ * Generates the component description.
+ * @return the component type description of
+ * the current component type
+ */
+ private Element generateComponentMetadata() {
+ Element element = new Element("composite", "");
+ if (m_name != null) {
+ element.addAttribute(new Attribute("name", m_name));
+ }
+ if (m_version != null) {
+ element.addAttribute(new Attribute("version", m_version));
+ }
+ if (! m_public) {
+ element.addAttribute(new Attribute("public", "false"));
+ }
+ for (int i = 0; i < m_contained.size(); i++) {
+ Instance inst = (Instance) m_contained.get(i);
+ element.addElement(inst.getElement());
+ }
+ for (int i = 0; i < m_imported.size(); i++) {
+ ImportedService inst = (ImportedService) m_imported.get(i);
+ element.addElement(inst.getElement());
+ }
+ for (int i = 0; i < m_instantiated.size(); i++) {
+ InstantiatedService inst = (InstantiatedService) m_instantiated.get(i);
+ element.addElement(inst.getElement());
+ }
+ for (int i = 0; i < m_exported.size(); i++) {
+ ExportedService inst = (ExportedService) m_exported.get(i);
+ element.addElement(inst.getElement());
+ }
+ for (int i = 0; i < m_provided.size(); i++) {
+ ProvidedService inst = (ProvidedService) m_provided.get(i);
+ element.addElement(inst.getElement());
+ }
+
+ // External handlers
+ for (int i = 0; i < m_handlers.size(); i++) {
+ HandlerConfiguration hc = (HandlerConfiguration) m_handlers.get(i);
+ element.addElement(hc.getElement());
+ }
+
+ return element;
+ }
+
+ /**
+ * Creates the component factory.
+ */
+ private void createFactory() {
+ ensureValidity();
+ m_metadata = generateComponentMetadata();
+ try {
+ m_factory = new CompositeFactory(m_context, m_metadata);
+ m_factory.start();
+ } catch (ConfigurationException e) {
+ throw new IllegalStateException("An exception occurs during factory initialization", e);
+ }
+
+ }
+
+
+
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java
new file mode 100644
index 0000000..86fd25c
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java
@@ -0,0 +1,188 @@
+/*
+ * 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.api.composite;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+
+/**
+ * Allows defining an exported service. A service export is the
+ * publication of service from the composite to the parent composite
+ * or global registry. The service export relies on a service dependency
+ * inside the composite. Matching services will be exported.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ExportedService implements HandlerConfiguration {
+
+ /**
+ * The exported specification.
+ */
+ private String m_specification;
+
+ /**
+ * The LDAP filter of the service dependency
+ * used to select the adequate service provider from
+ * the composite.
+ */
+ private String m_filter;
+
+ /**
+ * Is the dependency optional?
+ */
+ private boolean m_optional;
+
+ /**
+ * Is the dependency aggregate?
+ */
+ private boolean m_aggregate;
+
+ /**
+ * The dependency binding policy.
+ * Default: Dynamic policy.
+ */
+ private int m_policy = DependencyModel.DYNAMIC_BINDING_POLICY;
+
+ /**
+ * The dependency comparator.
+ * (used to compare service providers)
+ */
+ private String m_comparator;
+
+ /**
+ * Gets the exported service metadata.
+ * @return the 'provides' element describing
+ * the current dependency.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("provides", "");
+ dep.addAttribute(new Attribute("action", "export"));
+
+ dep.addAttribute(new Attribute("specification", m_specification));
+
+
+ if (m_filter != null) {
+ dep.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_comparator != null) {
+ dep.addAttribute(new Attribute("comparator", m_comparator));
+ }
+
+ if (m_optional) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ if (m_aggregate) {
+ dep.addAttribute(new Attribute("aggregate", "true"));
+ }
+
+ if (m_policy == DependencyModel.DYNAMIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic"));
+ } else if (m_policy == DependencyModel.STATIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "static"));
+ } else if (m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic-priority"));
+ }
+
+ return dep;
+ }
+
+ /**
+ * Sets the required service specification.
+ * @param spec the specification
+ * @return the current exported service.
+ */
+ public ExportedService setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the LDAP filter
+ * @return the current exported service
+ */
+ public ExportedService setFilter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency optionality.
+ * @param opt <code>true</code> to set the
+ * dependency to optional.
+ * @return the current exported service.
+ */
+ public ExportedService setOptional(boolean opt) {
+ m_optional = opt;
+ return this;
+ }
+
+ /**
+ * Sets the dependency cardinality.
+ * @param agg <code>true</code> to set the
+ * dependency to aggregate.
+ * @return the current exported service.
+ */
+ public ExportedService setAggregate(boolean agg) {
+ m_aggregate = agg;
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency binding policy.
+ * @param policy the binding policy
+ * @return the current exported service
+ */
+ public ExportedService setBindingPolicy(int policy) {
+ m_policy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency comparator.
+ * @param cmp the comparator class name
+ * @return the current exported service
+ */
+ public ExportedService setComparator(String cmp) {
+ m_comparator = cmp;
+ return this;
+ }
+
+
+ /**
+ * Checks dependency configuration validity.
+ */
+ private void ensureValidity() {
+ // Check specification
+ if (m_specification == null) {
+ throw new IllegalStateException("The specification of the exported service must be set");
+ }
+
+ // Check binding policy.
+ if (!(m_policy == DependencyModel.DYNAMIC_BINDING_POLICY || m_policy == DependencyModel.STATIC_BINDING_POLICY || m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY)) {
+ throw new IllegalStateException("Unknown binding policy : " + m_policy);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java
new file mode 100644
index 0000000..fbb994f
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java
@@ -0,0 +1,237 @@
+/*
+ * 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.api.composite;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+
+/**
+ * Allows defining an imported service. A service import is the
+ * publication of service from the parent composite
+ * or global registry inside the composite.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ImportedService implements HandlerConfiguration {
+
+ /**
+ * Scoping policy: composite.
+ */
+ public static final String COMPOSITE_SCOPE = "composite";
+
+ /**
+ * Scoping policy: global.
+ */
+ public static final String GLOBAL_SCOPE = "global";
+
+ /**
+ * Scoping policy: composite+global.
+ */
+ public static final String COMPOSITE_AND_GLOBAL_SCOPE = "composite+global";
+
+
+ /**
+ * The required specification.
+ */
+ private String m_specification;
+
+ /**
+ * The LDAP filter of the dependency.
+ */
+ private String m_filter;
+
+ /**
+ * Is the dependency optional?
+ */
+ private boolean m_optional;
+
+ /**
+ * Is the dependency aggregate?
+ */
+ private boolean m_aggregate;
+
+ /**
+ * The dependency binding policy.
+ * Default: Dynamic policy.
+ */
+ private int m_policy = DependencyModel.DYNAMIC_BINDING_POLICY;
+
+ /**
+ * The dependency comparator.
+ * (used to compare service providers)
+ */
+ private String m_comparator;
+
+ /**
+ * The dependency id.
+ */
+ private String m_id;
+
+ /**
+ * Dependency scope.
+ */
+ private String m_scope = COMPOSITE_SCOPE;
+
+ /**
+ * Gets the dependency metadata.
+ * @return the 'requires' element describing
+ * the current dependency.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("subservice", "");
+ dep.addAttribute(new Attribute("action", "import"));
+
+ dep.addAttribute(new Attribute("specification", m_specification));
+ dep.addAttribute(new Attribute("scope", m_scope));
+
+
+ if (m_filter != null) {
+ dep.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_comparator != null) {
+ dep.addAttribute(new Attribute("comparator", m_comparator));
+ }
+
+ if (m_id != null) {
+ dep.addAttribute(new Attribute("id", m_id));
+ }
+
+ if (m_optional) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ if (m_aggregate) {
+ dep.addAttribute(new Attribute("aggregate", "true"));
+ }
+
+ if (m_policy == DependencyModel.DYNAMIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic"));
+ } else if (m_policy == DependencyModel.STATIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "static"));
+ } else if (m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic-priority"));
+ }
+
+ return dep;
+ }
+
+ /**
+ * Sets the required service specification.
+ * @param spec the specification
+ * @return the current imported sub-service.
+ */
+ public ImportedService setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the LDAP filter
+ * @return the current imported sub-service
+ */
+ public ImportedService setFilter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency optionality.
+ * @param opt <code>true</code> to set the
+ * dependency to optional.
+ * @return the current imported sub-service.
+ */
+ public ImportedService setOptional(boolean opt) {
+ m_optional = opt;
+ return this;
+ }
+
+ /**
+ * Sets the dependency cardinality.
+ * @param agg <code>true</code> to set the
+ * dependency to aggregate.
+ * @return the current imported sub-service.
+ */
+ public ImportedService setAggregate(boolean agg) {
+ m_aggregate = agg;
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency binding policy.
+ * @param policy the binding policy
+ * @return the current imported sub-service
+ */
+ public ImportedService setBindingPolicy(int policy) {
+ m_policy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency comparator.
+ * @param cmp the comparator class name
+ * @return the current imported sub-service
+ */
+ public ImportedService setComparator(String cmp) {
+ m_comparator = cmp;
+ return this;
+ }
+
+
+ /**
+ * Sets the dependency id.
+ * @param id the dependency id.
+ * @return the current imported sub-service.
+ */
+ public ImportedService setId(String id) {
+ m_id = id;
+ return this;
+ }
+
+ /**
+ * Sets the dependency scope.
+ * @param scope the dependency scope (global, composite or
+ * composite+global).
+ * @return the current imported sub-service.
+ */
+ public ImportedService setScope(String scope) {
+ m_scope = scope;
+ return this;
+ }
+
+ /**
+ * Checks dependency configuration validity.
+ */
+ private void ensureValidity() {
+ // Check specification
+ if (m_specification == null) {
+ throw new IllegalStateException("The specification of the imported service must be set");
+ }
+
+ // Check binding policy.
+ if (!(m_policy == DependencyModel.DYNAMIC_BINDING_POLICY || m_policy == DependencyModel.STATIC_BINDING_POLICY || m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY)) {
+ throw new IllegalStateException("Unknown binding policy : " + m_policy);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java
new file mode 100644
index 0000000..0d652b4
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java
@@ -0,0 +1,246 @@
+/*
+ * 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.api.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows defining a contained instance. A contained instance is like
+ * an instance declaration but the instance is created in the composite.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Instance implements HandlerConfiguration {
+
+ /**
+ * Targeted component type.
+ */
+ private String m_type;
+
+ /**
+ * Configuration.
+ */
+ private List m_conf = new ArrayList();
+
+ /**
+ * Creates a Instance.
+ * @param type the targeted type.
+ */
+ public Instance(String type) {
+ m_type = type;
+ }
+
+ /**
+ * Adds the string property.
+ * @param name property name
+ * @param value property value
+ * @return the current instance
+ */
+ public Instance addProperty(String name, String value) {
+ Element elem = new Element("property", "");
+ m_conf.add(elem);
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("value", value));
+ return this;
+ }
+
+ /**
+ * Adds a list property.
+ * @param name property name
+ * @param values the list
+ * @return the current instance
+ */
+ public Instance addProperty(String name, List values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "list"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.size(); i++) {
+ Object obj = values.get(i);
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ if (obj instanceof String) {
+ e.addAttribute(new Attribute("value", obj.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds an array property.
+ * @param name the property name
+ * @param values the array
+ * @return the current instance
+ */
+ public Instance addProperty(String name, String[] values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "array"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.length; i++) {
+ Object obj = values[i];
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ e.addAttribute(new Attribute("value", obj.toString()));
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a vector property.
+ * @param name the property name
+ * @param values the vector
+ * @return the current instance
+ */
+ public Instance addProperty(String name, Vector values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "vector"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.size(); i++) {
+ Object obj = values.get(i);
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ if (obj instanceof String) {
+ e.addAttribute(new Attribute("value", obj.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a map property.
+ * @param name the property name
+ * @param values the map
+ * @return the current instance
+ */
+ public Instance addProperty(String name, Map values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "map"));
+
+ m_conf.add(elem);
+ Set entries = values.entrySet();
+ Iterator it = entries.iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Entry) it.next();
+ Element e = new Element("property", "");
+ elem.addElement(e);
+
+ String n = (String) entry.getKey();
+ Object v = entry.getValue();
+ if (v instanceof String) {
+ e.addAttribute(new Attribute("name", n));
+ e.addAttribute(new Attribute("value", v.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a dictionary property.
+ * @param name the property name
+ * @param values the dictionary
+ * @return the current instance
+ */
+ public Instance addProperty(String name, Dictionary values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "dictionary"));
+
+ m_conf.add(elem);
+ Enumeration e = values.keys();
+ while (e.hasMoreElements()) {
+ Element el = new Element("property", "");
+ elem.addElement(el);
+
+ String n = (String) e.nextElement();
+ Object v = values.get(n);
+ if (v instanceof String) {
+ el.addAttribute(new Attribute("name", n));
+ el.addAttribute(new Attribute("value", v.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Ensures the validity of the instance description.
+ */
+ private void ensureValidity() {
+ if (m_type == null) {
+ throw new IllegalStateException(
+ "Invalid containted instance configuration : the component type is not set");
+ }
+ }
+
+ /**
+ * Gets the instance description in the Element-Attribute form.
+ * @return the root Element of the instance description
+ * @see org.apache.felix.ipojo.api.HandlerConfiguration#getElement()
+ */
+ public Element getElement() {
+ ensureValidity();
+ Element instance = new Element("instance", "");
+ instance.addAttribute(new Attribute("component", m_type));
+ for (int i = 0; i < m_conf.size(); i++) {
+ Element elem = (Element) m_conf.get(i);
+ instance.addElement(elem);
+ }
+ return instance;
+ }
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java
new file mode 100644
index 0000000..fa67c02
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java
@@ -0,0 +1,362 @@
+/*
+ * 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.api.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+
+/**
+ * Allows defining an instantiated sub-service. An instantiated sub-
+ * service will be reified by instances publishing the required service.
+ * Those instances are created from public factories
+ * inside the composite.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstantiatedService implements HandlerConfiguration {
+
+ /**
+ * The required specification.
+ */
+ private String m_specification;
+
+ /**
+ * The LDAP filter of the dependency.
+ */
+ private String m_filter;
+
+ /**
+ * Is the dependency optional?
+ */
+ private boolean m_optional;
+
+ /**
+ * Is the dependency aggregate?
+ */
+ private boolean m_aggregate;
+
+ /**
+ * The dependency binding policy. Default: Dynamic policy.
+ */
+ private int m_policy = DependencyModel.DYNAMIC_BINDING_POLICY;
+
+ /**
+ * The dependency comparator. (used to compare service providers)
+ */
+ private String m_comparator;
+
+ /**
+ * Instance configuration List of Element (Property).
+ */
+ private List m_conf = new ArrayList();
+
+ /**
+ * Gets the dependency metadata.
+ * @return the 'subservice' element describing the current
+ * instantiated service.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("subservice", "");
+ dep.addAttribute(new Attribute("action", "instantiate"));
+
+ dep.addAttribute(new Attribute("specification", m_specification));
+
+ if (m_filter != null) {
+ dep.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_comparator != null) {
+ dep.addAttribute(new Attribute("comparator", m_comparator));
+ }
+
+ if (m_optional) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ if (m_aggregate) {
+ dep.addAttribute(new Attribute("aggregate", "true"));
+ }
+
+ if (m_policy == DependencyModel.DYNAMIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic"));
+ } else if (m_policy == DependencyModel.STATIC_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "static"));
+ } else if (m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ dep.addAttribute(new Attribute("policy", "dynamic-priority"));
+ }
+
+ for (int i = 0; i < m_conf.size(); i++) {
+ Element elem = (Element) m_conf.get(i);
+ dep.addElement(elem);
+ }
+
+ return dep;
+ }
+
+ /**
+ * Adds a string property.
+ * @param name the property name
+ * @param value the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, String value) {
+ Element elem = new Element("property", "");
+ m_conf.add(elem);
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("value", value));
+ return this;
+ }
+
+ /**
+ * Adds a list property.
+ * @param name the property name
+ * @param values the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, List values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "list"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.size(); i++) {
+ Object obj = values.get(i);
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ if (obj instanceof String) {
+ e.addAttribute(new Attribute("value", obj.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds an array property.
+ * @param name the property name
+ * @param values the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, String[] values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "array"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.length; i++) {
+ Object obj = values[i];
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ e.addAttribute(new Attribute("value", obj.toString()));
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a vector property.
+ * @param name the property name
+ * @param values the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, Vector values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "vector"));
+
+ m_conf.add(elem);
+
+ for (int i = 0; i < values.size(); i++) {
+ Object obj = values.get(i);
+ Element e = new Element("property", "");
+ elem.addElement(e);
+ if (obj instanceof String) {
+ e.addAttribute(new Attribute("value", obj.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a map property.
+ * @param name the property name
+ * @param values the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, Map values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "map"));
+
+ m_conf.add(elem);
+ Set entries = values.entrySet();
+ Iterator it = entries.iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Entry) it.next();
+ Element e = new Element("property", "");
+ elem.addElement(e);
+
+ String n = (String) entry.getKey();
+ Object v = entry.getValue();
+ if (v instanceof String) {
+ e.addAttribute(new Attribute("name", n));
+ e.addAttribute(new Attribute("value", v.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds a dictionary property.
+ * @param name the property name
+ * @param values the property value
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService addProperty(String name, Dictionary values) {
+ Element elem = new Element("property", "");
+ elem.addAttribute(new Attribute("name", name));
+ elem.addAttribute(new Attribute("type", "dictionary"));
+
+ m_conf.add(elem);
+ Enumeration e = values.keys();
+ while (e.hasMoreElements()) {
+ Element el = new Element("property", "");
+ elem.addElement(el);
+
+ String n = (String) e.nextElement();
+ Object v = values.get(n);
+ if (v instanceof String) {
+ el.addAttribute(new Attribute("name", n));
+ el.addAttribute(new Attribute("value", v.toString()));
+ } else {
+ // TODO
+ throw new UnsupportedOperationException(
+ "Complex properties are not supported yet");
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the required service specification.
+ * @param spec the specification
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the LDAP filter
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setFilter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+ /**
+ * Sets the dependency optionality.
+ * @param opt <code>true</code> to set the dependency to optional.
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setOptional(boolean opt) {
+ m_optional = opt;
+ return this;
+ }
+
+ /**
+ * Sets the dependency cardinality.
+ * @param agg <code>true</code> to set the dependency to aggregate.
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setAggregate(boolean agg) {
+ m_aggregate = agg;
+ return this;
+ }
+
+ /**
+ * Sets the dependency binding policy.
+ * @param policy the binding policy
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setBindingPolicy(int policy) {
+ m_policy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the dependency comparator.
+ * @param cmp the comparator class name
+ * @return the current instantiated sub-service
+ */
+ public InstantiatedService setComparator(String cmp) {
+ m_comparator = cmp;
+ return this;
+ }
+
+ /**
+ * Checks dependency configuration validity.
+ */
+ private void ensureValidity() {
+ // Check specification
+ if (m_specification == null) {
+ throw new IllegalStateException(
+ "The specification of the instantiated service must be set");
+ }
+
+ // Check binding policy.
+ if (!(m_policy == DependencyModel.DYNAMIC_BINDING_POLICY
+ || m_policy == DependencyModel.STATIC_BINDING_POLICY || m_policy == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY)) {
+ throw new IllegalStateException("Unknown binding policy : "
+ + m_policy);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java
new file mode 100644
index 0000000..922c992
--- /dev/null
+++ b/ipojo/runtime/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java
@@ -0,0 +1,112 @@
+/*
+ * 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.api.composite;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Allows defining a provided service. A provided service is a service
+ * 'implemented' by the composite. This implementations relies (by
+ * delegation) on contained instances and services.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedService implements HandlerConfiguration {
+ /**
+ * Delegation policy: all.
+ */
+ public static final String ALL_POLICY = "all";
+
+ /**
+ * Delegation policy: one.
+ */
+ public static final String ONE_POLICY = "one";
+
+ /**
+ * The provided specification.
+ */
+ private String m_specification;
+
+ /**
+ * List of delegation.
+ * List of Element ({delegation $method $policy})
+ */
+ private List m_delegation = new ArrayList();
+
+
+ /**
+ * Gets the provided element.
+ * @return the 'provides' element describing
+ * the current provided service.
+ */
+ public Element getElement() {
+ ensureValidity();
+
+ Element dep = new Element("provides", "");
+ dep.addAttribute(new Attribute("action", "implement"));
+
+ dep.addAttribute(new Attribute("specification", m_specification));
+
+ for (int i = 0; i < m_delegation.size(); i++) {
+ dep.addElement((Element) m_delegation.get(i));
+ }
+
+ return dep;
+ }
+
+ /**
+ * Sets the provided service specification.
+ * @param spec the specification
+ * @return the current provided service.
+ */
+ public ProvidedService setSpecification(String spec) {
+ m_specification = spec;
+ return this;
+ }
+
+ /**
+ * Sets the delegation policy of the given method.
+ * @param method the method name
+ * @param policy the delegation policy
+ * @return the current exported service.
+ */
+ public ProvidedService setDelegation(String method, String policy) {
+ Element element = new Element("delegation", "");
+ element.addAttribute(new Attribute("method", method));
+ element.addAttribute(new Attribute("policy", policy));
+ m_delegation.add(element);
+ return this;
+ }
+
+
+ /**
+ * Checks provided service configuration validity.
+ */
+ private void ensureValidity() {
+ // Check specification
+ if (m_specification == null) {
+ throw new IllegalStateException("The specification of the implemented service must be set");
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java
new file mode 100644
index 0000000..b6641f7
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.api;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Test the {@link Dependency} methods.
+ */
+public class DependencyTest extends TestCase {
+
+ public void testConstructorParameter() {
+ Dependency dep = new Dependency().setConstructorParameter(1);
+ Element elem = dep.getElement();
+ assertEquals("1", elem.getAttribute("constructor-parameter"));
+ }
+
+ public void testField() {
+ Dependency dep = new Dependency().setField("field");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ }
+
+ public void testAggregate() {
+ Dependency dep = new Dependency().setField("field")
+ .setAggregate(true);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("aggregate"));
+ }
+
+ public void testOptional() {
+ Dependency dep = new Dependency().setField("field")
+ .setOptional(true);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ }
+
+ public void testNullable() {
+ Dependency dep = new Dependency().setField("field").setOptional(true)
+ .setNullable(false);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals("false", elem.getAttribute("nullable"));
+
+ dep = new Dependency().setField("field").setOptional(true)
+ .setNullable(true);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals(null, elem.getAttribute("nullable")); // Default value.
+ }
+
+ public void testFilter() {
+ Dependency dep = new Dependency().setField("field")
+ .setFilter("(my.prop=1)");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("(my.prop=1)", elem.getAttribute("filter"));
+ }
+
+ public void testFrom() {
+ Dependency dep = new Dependency().setField("field")
+ .setFrom("foo");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("foo", elem.getAttribute("from"));
+ }
+
+ public void testId() {
+ Dependency dep = new Dependency().setField("field")
+ .setId("foo");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("foo", elem.getAttribute("id"));
+ }
+
+ public void testProxy() {
+ Dependency dep = new Dependency().setField("field").setOptional(true)
+ .setProxy(false);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals("false", elem.getAttribute("proxy"));
+ }
+
+ public void testComparator() {
+ Dependency dep = new Dependency().setField("field")
+ .setComparator("my.Comparator");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("my.Comparator", elem.getAttribute("comparator"));
+ }
+
+ public void testBindingPolicy() {
+ Dependency dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.DYNAMIC_PRIORITY);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("dynamic-priority", elem.getAttribute("policy"));
+
+ dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.STATIC);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("static", elem.getAttribute("policy"));
+
+ dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.DYNAMIC);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("dynamic", elem.getAttribute("policy"));
+ }
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java
new file mode 100644
index 0000000..e1a3568
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.api;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Test the {@link Property} methods.
+ */
+public class PropertyTest extends TestCase {
+
+ public void testConstructorParameter() {
+ Property prop = new Property().setConstructorParameter(1);
+ Element elem = prop.getElement();
+ assertEquals("1", elem.getAttribute("constructor-parameter"));
+ }
+
+ public void testField() {
+ Property prop = new Property().setField("field");
+ Element elem = prop.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ }
+
+ public void testMandatoryPropertyWithValue() {
+ Property prop = new Property().setField("field")
+ .setMandatory(true)
+ .setName("prop")
+ .setValue("foo")
+ .setImmutable(true);
+ Element elem = prop.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("prop", elem.getAttribute("name"));
+ assertEquals("foo", elem.getAttribute("value"));
+ assertEquals("true", elem.getAttribute("mandatory"));
+ assertEquals("true", elem.getAttribute("immutable"));
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java
new file mode 100644
index 0000000..02c0bb1
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.api;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the {@link Service} methods.
+ */
+public class ServiceTest extends TestCase {
+
+ public void testServiceController() {
+ Service svc = new Service().setServiceController("m_controller", true);
+
+ Element elem = svc.getElement();
+ assertTrue(elem.getElements("controller").length == 1);
+ Element controller = elem.getElements("controller")[0];
+ assertEquals("m_controller", controller.getAttribute("field"));
+ assertEquals("true", controller.getAttribute("value"));
+
+ svc = new Service().setServiceController("m_controller", false);
+ elem = svc.getElement();
+ assertTrue(elem.getElements("controller").length == 1);
+ controller = elem.getElements("controller")[0];
+ assertEquals("m_controller", controller.getAttribute("field"));
+ assertEquals("false", controller.getAttribute("value"));
+ }
+
+ public void testRegistrationCallbacks() {
+ Service svc = new Service()
+ .setPostRegistrationCallback("registration")
+ .setPostUnregistrationCallback("unregistration");
+
+ Element elem = svc.getElement();
+ assertEquals("registration", elem.getAttribute("post-registration"));
+ assertEquals("unregistration", elem.getAttribute("post-unregistration"));
+ }
+
+ public void testSpecificationWithOneService() {
+ Service svc = new Service()
+ .setSpecification("org.foo.acme.MyService");
+
+ Element elem = svc.getElement();
+ assertEquals("org.foo.acme.MyService", elem.getAttribute("specifications"));
+ }
+
+ public void testSpecificationWithTwoServices() {
+ List spec = new ArrayList();
+ spec.add("org.foo.acme.MyService");
+ spec.add("org.foo.acme.MyService2");
+ Service svc = new Service()
+ .setSpecifications(spec);
+
+ Element elem = svc.getElement();
+ assertEquals("{org.foo.acme.MyService,org.foo.acme.MyService2}", elem.getAttribute("specifications"));
+ }
+
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ExportedServiceTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ExportedServiceTest.java
new file mode 100644
index 0000000..3a7dd37
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ExportedServiceTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.api.composite;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Test about {@link ExportedService}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ExportedServiceTest extends TestCase {
+
+ //
+ // <comp:composite name="composite.export.5" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // aggregate="true" optional="true" filter="(!(instance.name=export))"
+ // scope="composite" />
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // filter="(instance.name=foo1)" />
+ // </comp:composite>
+
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // />
+ /**
+ * Tests simple export.
+ */
+ public void testSimple() {
+ ExportedService svc = new ExportedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.BazService");
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.BazService",
+ spec);
+ }
+
+ /**
+ * Tests a malformed export.
+ */
+ public void testBad() {
+ ExportedService svc = new ExportedService()
+ // .setSpecification("org.apache.felix.ipojo.test.composite.service.BarService")
+ // NO SPEC
+ ;
+ try {
+ svc.getElement();
+ fail("Invalid element accepted");
+ } catch (IllegalStateException e) {
+ // OK
+ }
+ }
+
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // aggregate="true" />
+ /**
+ * Tests aggregate export.
+ */
+ public void testAggregate() {
+ ExportedService svc = new ExportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.BazService")
+ .setAggregate(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String agg = elem.getAttribute("aggregate");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.BazService",
+ spec);
+ assertEquals("aggregate", "true", agg);
+ }
+
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // optional="true" />
+ /**
+ * Tests optional export.
+ */
+ public void testOptional() {
+ ExportedService svc = new ExportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.BazService")
+ .setOptional(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String opt = elem.getAttribute("optional");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.BazService",
+ spec);
+ assertEquals("optional", "true", opt);
+ }
+
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // aggregate="true" optional="true" />
+ /**
+ * Tests optional and aggregate export.
+ */
+ public void testOptionalAndAggregate() {
+ ExportedService svc = new ExportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setOptional(true).setAggregate(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String opt = elem.getAttribute("optional");
+ String agg = elem.getAttribute("aggregate");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("optional", "true", opt);
+ assertEquals("aggregate", "true", agg);
+ }
+
+ // <comp:provides action="export"
+ // specification="org.apache.felix.ipojo.test.composite.service.BazService"
+ // filter="(instance.name=foo1)" />
+ /**
+ * Tests filtered export.
+ */
+ public void testFilter() {
+ ExportedService svc = new ExportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setFilter("(&(int=2)(long=40))");
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String filter = elem.getAttribute("filter");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("filter", "(&(int=2)(long=40))", filter);
+ }
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ImportedServiceTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ImportedServiceTest.java
new file mode 100644
index 0000000..3c889bf
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/ImportedServiceTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.api.composite;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Tests about {@link ImportedService}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ImportedServiceTest extends TestCase {
+
+ // <comp:composite name="composite.requires.1" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.FooService"
+ // scope="composite" />
+ // </comp:composite>
+ /**
+ * Simple test.
+ */
+ public void testSimple() {
+ ImportedService svc = new ImportedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.FooService");
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ }
+
+ /**
+ * Malformed import.
+ */
+ public void testBad() {
+ ImportedService svc = new ImportedService()
+ // .setSpecification("org.apache.felix.ipojo.test.composite.service.BarService")
+ // NO SPEC
+ ;
+ try {
+ svc.getElement();
+ fail("Invalid element accepted");
+ } catch (IllegalStateException e) {
+ // OK
+ }
+ }
+
+ /**
+ * Tests scopes.
+ */
+ public void testScope() {
+ ImportedService svc = new ImportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setScope(ImportedService.COMPOSITE_SCOPE);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String scope = elem.getAttribute("scope");
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("scope", "composite", scope);
+
+ }
+
+ //
+ // <comp:composite name="composite.requires.2" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.FooService"
+ // aggregate="true" scope="composite" />
+ // </comp:composite>
+ /**
+ * Tests aggregate.
+ */
+ public void testAggregate() {
+ ImportedService svc = new ImportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setScope(ImportedService.COMPOSITE_SCOPE).setAggregate(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String scope = elem.getAttribute("scope");
+ String agg = elem.getAttribute("aggregate");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("scope", "composite", scope);
+ assertEquals("aggregate", "true", agg);
+ }
+
+ //
+ // <comp:composite name="composite.requires.3" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.FooService"
+ // optional="true" scope="composite" />
+ // </comp:composite>
+ /**
+ * Tests optional.
+ */
+ public void testOptional() {
+ ImportedService svc = new ImportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setScope(ImportedService.COMPOSITE_SCOPE).setOptional(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String scope = elem.getAttribute("scope");
+ String opt = elem.getAttribute("optional");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("scope", "composite", scope);
+ assertEquals("optional", "true", opt);
+ }
+
+ //
+ // <comp:composite name="composite.requires.4" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.FooService"
+ // optional="true" aggregate="true" scope="comp:composite" />
+ // </comp:composite>
+ /**
+ * Tests optional and aggregate.
+ */
+ public void testOptionalAndAggregate() {
+ ImportedService svc = new ImportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setScope(ImportedService.COMPOSITE_SCOPE).setOptional(true)
+ .setAggregate(true);
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String scope = elem.getAttribute("scope");
+ String opt = elem.getAttribute("optional");
+ String agg = elem.getAttribute("aggregate");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("scope", "composite", scope);
+ assertEquals("optional", "true", opt);
+ assertEquals("aggregate", "true", agg);
+ }
+
+ //
+ // <comp:composite name="composite.requires.5" architecture="true">
+ // <subservice action="import"
+ // specification="org.apache.felix.ipojo.test.composite.service.FooService"
+ // filter="(&(int=2)(long=40))" scope="composite" />
+ // </comp:composite>
+ /**
+ * Tests filter.
+ */
+ public void testFilter() {
+ ImportedService svc = new ImportedService().setSpecification(
+ "org.apache.felix.ipojo.test.composite.service.FooService")
+ .setScope(ImportedService.COMPOSITE_SCOPE).setFilter(
+ "(&(int=2)(long=40))");
+
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String scope = elem.getAttribute("scope");
+ String filter = elem.getAttribute("filter");
+
+ assertEquals("spec",
+ "org.apache.felix.ipojo.test.composite.service.FooService",
+ spec);
+ assertEquals("scope", "composite", scope);
+ assertEquals("filter", "(&(int=2)(long=40))", filter);
+ }
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstanceTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstanceTest.java
new file mode 100644
index 0000000..02ab484
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstanceTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.api.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Tests about {@link Instance}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstanceTest extends TestCase {
+
+ /**
+ * One simple instance.
+ */
+ public void testJustComponent() {
+ Instance inst = new Instance("mycmp");
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ assertEquals("Check component attribute", "mycmp", cmp);
+ }
+
+ /**
+ * Sting property.
+ */
+ public void testStringProp() {
+ Instance inst = new Instance("mycmp");
+ inst.addProperty("p1", "v1");
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertEquals("Check property 0 - value", "v1", v);
+ assertNull("Check property 0 - type", t);
+
+ }
+
+ /**
+ * Several properties.
+ */
+ public void testStringProps() {
+ Instance inst = new Instance("mycmp");
+ inst.addProperty("p1", "v1");
+ inst.addProperty("p2", "v2");
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 2, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ assertEquals("Check property 0 - name", "p1", n);
+ assertEquals("Check property 0 - value", "v1", v);
+ n = elems[1].getAttribute("name");
+ v = elems[1].getAttribute("value");
+ assertEquals("Check property 1 - name", "p2", n);
+ assertEquals("Check property 1 - value", "v2", v);
+ }
+
+ /**
+ * List property.
+ */
+ public void testListProp() {
+ Instance inst = new Instance("mycmp");
+ List list = new ArrayList();
+ list.add("a");
+ list.add("a");
+ list.add("a");
+
+ inst.addProperty("p1", list);
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertNull("Check property 0 - value", v);
+ assertEquals("Check property 0 - type", "list", t);
+
+
+ Element[] subs = elems[0].getElements();
+ assertEquals("Check the number of sub-elements", 3, subs.length);
+ for (int i = 0; i < subs.length; i++) {
+ Element a = subs[i];
+ assertEquals("Check the value of " + i, "a", a.getAttribute("value"));
+ assertNull("Check the name of " + i, a.getAttribute("name"));
+
+ }
+ }
+
+ /**
+ * Array property.
+ */
+ public void testArrayProp() {
+ Instance inst = new Instance("mycmp");
+ String[] list = new String[] {"a", "a", "a"};
+
+ inst.addProperty("p1", list);
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertNull("Check property 0 - value", v);
+ assertEquals("Check property 0 - type", "array", t);
+
+
+ Element[] subs = elems[0].getElements();
+ assertEquals("Check the number of sub-elements", 3, subs.length);
+ for (int i = 0; i < subs.length; i++) {
+ Element a = subs[i];
+ assertEquals("Check the value of " + i, "a", a.getAttribute("value"));
+ assertNull("Check the name of " + i, a.getAttribute("name"));
+
+ }
+ }
+
+ /**
+ * Vector property.
+ */
+ public void testVectorProp() {
+ Instance inst = new Instance("mycmp");
+ Vector list = new Vector();
+ list.add("a");
+ list.add("a");
+ list.add("a");
+
+ inst.addProperty("p1", list);
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertNull("Check property 0 - value", v);
+ assertEquals("Check property 0 - type", "vector", t);
+
+
+ Element[] subs = elems[0].getElements();
+ assertEquals("Check the number of sub-elements", 3, subs.length);
+ for (int i = 0; i < subs.length; i++) {
+ Element a = subs[i];
+ assertEquals("Check the value of " + i, "a", a.getAttribute("value"));
+ assertNull("Check the name of " + i, a.getAttribute("name"));
+
+ }
+ }
+
+ /**
+ * Map property.
+ */
+ public void testMapProp() {
+ Instance inst = new Instance("mycmp");
+ Map map = new HashMap();
+ map.put("p1", "b");
+ map.put("p2", "b");
+ map.put("p3", "b");
+
+ inst.addProperty("p1", map);
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertNull("Check property 0 - value", v);
+ assertEquals("Check property 0 - type", "map", t);
+
+ Element[] subs = elems[0].getElements();
+ assertEquals("Check the number of sub-elements", 3, subs.length);
+ for (int i = 0; i < subs.length; i++) {
+ Element a = subs[i];
+ assertEquals("Check the value of " + i, "b", a.getAttribute("value"));
+ assertNotNull("Check the name of " + i, a.getAttribute("name"));
+
+ }
+ }
+
+ /**
+ * Dictionary property.
+ */
+ public void testDictProp() {
+ Instance inst = new Instance("mycmp");
+ Dictionary map = new Properties();
+ map.put("p1", "b");
+ map.put("p2", "b");
+ map.put("p3", "b");
+
+ inst.addProperty("p1", map);
+ Element elem = inst.getElement();
+ String cmp = elem.getAttribute("component");
+ Element[] elems = elem.getElements();
+ assertEquals("Check component attribute", "mycmp", cmp);
+ assertNotNull("Check properties", elems);
+ assertEquals("Check properties count", 1, elems.length);
+ String n = elems[0].getAttribute("name");
+ String v = elems[0].getAttribute("value");
+ String t = elems[0].getAttribute("type");
+
+
+ assertEquals("Check property 0 - name", "p1", n);
+ assertNull("Check property 0 - value", v);
+ assertEquals("Check property 0 - type", "dictionary", t);
+
+
+ Element[] subs = elems[0].getElements();
+ assertEquals("Check the number of sub-elements", 3, subs.length);
+ for (int i = 0; i < subs.length; i++) {
+ Element a = subs[i];
+ assertEquals("Check the value of " + i, "b", a.getAttribute("value"));
+ assertNotNull("Check the name of " + i, a.getAttribute("name"));
+
+ }
+ }
+
+}
diff --git a/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstantiatedServiceTest.java b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstantiatedServiceTest.java
new file mode 100644
index 0000000..ec878bf
--- /dev/null
+++ b/ipojo/runtime/api/src/test/java/org/apache/felix/ipojo/api/composite/InstantiatedServiceTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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.api.composite;
+
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Tests about {@link InstantiatedService}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstantiatedServiceTest extends TestCase {
+
+// <comp:composite name="composite.bar.1" architecture="true">
+// <subservice action="instantiate" specification="org.apache.felix.ipojo.test.composite.service.BarService"/>
+//</comp:composite>
+
+ /**
+ * Simple test.
+ */
+ public void testSimple() {
+ InstantiatedService svc = new InstantiatedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.BarService");
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String action = elem.getAttribute("action");
+
+ assertEquals("spec" , "org.apache.felix.ipojo.test.composite.service.BarService", spec);
+ assertEquals("action" , "instantiate", action);
+ }
+
+ /**
+ * Malformed instantiated service.
+ */
+ public void testBad() {
+ InstantiatedService svc = new InstantiatedService()
+ //.setSpecification("org.apache.felix.ipojo.test.composite.service.BarService") NO SPEC
+ ;
+ try {
+ svc.getElement();
+ fail("Invalid element accepted");
+ } catch (IllegalStateException e) {
+ // OK
+ }
+ }
+
+
+
+
+//
+//<comp:composite name="composite.bar.2" architecture="true">
+// <subservice action="instantiate" specification="org.apache.felix.ipojo.test.composite.service.BarService" aggregate="true"/>
+//</comp:composite>
+
+ /**
+ * Aggregate.
+ */
+ public void testAggregate() {
+ InstantiatedService svc = new InstantiatedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.BarService")
+ .setAggregate(true);
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String action = elem.getAttribute("action");
+ String agg = elem.getAttribute("aggregate");
+
+
+ assertEquals("spec" , "org.apache.felix.ipojo.test.composite.service.BarService", spec);
+ assertEquals("action" , "instantiate", action);
+ assertEquals("aggregate" , "true", agg);
+
+ }
+
+//
+//<comp:composite name="composite.bar.3" architecture="true">
+// <subservice action="instantiate" specification="org.apache.felix.ipojo.test.composite.service.BarService" optional="true"/>
+//</comp:composite>
+ /**
+ * Optional.
+ */
+ public void testOptional() {
+ InstantiatedService svc = new InstantiatedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.BarService")
+ .setOptional(true);
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String action = elem.getAttribute("action");
+ String agg = elem.getAttribute("aggregate");
+ String opt = elem.getAttribute("optional");
+
+ assertEquals("spec" , "org.apache.felix.ipojo.test.composite.service.BarService", spec);
+ assertEquals("action" , "instantiate", action);
+ assertNull("aggregate" , agg);
+ assertEquals("optional" , "true", opt);
+ }
+
+//
+//<comp:composite name="composite.bar.4" architecture="true">
+// <subservice action="instantiate" specification="org.apache.felix.ipojo.test.composite.service.FooService" aggregate="true" optional="true"/>
+//</comp:composite>
+ /**
+ * Aggregate and optional.
+ */
+ public void testOptionalAndAggregate() {
+ InstantiatedService svc = new InstantiatedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.FooService")
+ .setOptional(true)
+ .setAggregate(true);
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String action = elem.getAttribute("action");
+ String agg = elem.getAttribute("aggregate");
+ String opt = elem.getAttribute("optional");
+
+ assertEquals("spec" , "org.apache.felix.ipojo.test.composite.service.FooService", spec);
+ assertEquals("action" , "instantiate", action);
+ assertEquals("aggregate" , "true", agg);
+ assertEquals("optional" , "true", opt);
+ }
+
+//
+//<comp:composite name="composite.bar.5-accept" architecture="true">
+// <subservice action="instantiate" specification="org.apache.felix.ipojo.test.composite.service.FooService">
+// <property name="boolean" value="true"/>
+// <property name="string" value="foo"/>
+// <property name="strAprop" value="{foo, bar, baz}"/>
+// <property name="int" value="5"/>
+// </subservice>
+//</comp:composite>
+ /**
+ * Instance configuration.
+ */
+ public void testWithConfiguration() {
+ InstantiatedService svc = new InstantiatedService()
+ .setSpecification("org.apache.felix.ipojo.test.composite.service.FooService")
+ .addProperty("boolean", "true")
+ .addProperty("string", "foo")
+ .addProperty("stringAprop", new String[] {"foo", "bar", "baz" })
+ .addProperty("int", "5");
+ Element elem = svc.getElement();
+ String spec = elem.getAttribute("specification");
+ String action = elem.getAttribute("action");
+ String agg = elem.getAttribute("aggregate");
+ String opt = elem.getAttribute("optional");
+
+ assertEquals("spec" , "org.apache.felix.ipojo.test.composite.service.FooService", spec);
+ assertEquals("action" , "instantiate", action);
+ assertNull("aggregate" , agg);
+ assertNull("optional" , opt);
+
+ Element[] props = elem.getElements("property");
+ assertEquals("Number of properties", 4, props.length);
+ String n0 = props[0].getAttribute("name");
+ String v0 = props[0].getAttribute("value");
+ assertEquals("n0" , "boolean", n0);
+ assertEquals("v0" , "true", v0);
+
+ String n1 = props[1].getAttribute("name");
+ String v1 = props[1].getAttribute("value");
+ assertEquals("n1" , "string", n1);
+ assertEquals("v1" , "foo", v1);
+
+ String n2 = props[2].getAttribute("name");
+ String v2 = props[2].getAttribute("value");
+ String t2 = props[2].getAttribute("type");
+ Element[] sub = props[2].getElements();
+ assertEquals("Number of sub-properties", 3, sub.length);
+ assertEquals("n2", "stringAprop", n2);
+ assertNull("v2", v2);
+ assertEquals("t2", "array", t2);
+
+ String n20 = sub[0].getAttribute("name");
+ String v20 = sub[0].getAttribute("value");
+ assertNull("n20" , n20);
+ assertEquals("v20" , "foo", v20);
+ String n21 = sub[1].getAttribute("name");
+ String v21 = sub[1].getAttribute("value");
+ assertNull("n21" , n21);
+ assertEquals("v21" , "bar", v21);
+ String n22 = sub[2].getAttribute("name");
+ String v22 = sub[2].getAttribute("value");
+ assertNull("n22" , n22);
+ assertEquals("v22" , "baz", v22);
+
+ String n3 = props[3].getAttribute("name");
+ String v3 = props[3].getAttribute("value");
+ assertEquals("n3" , "int", n3);
+ assertEquals("v3" , "5", v3);
+ }
+
+
+}
diff --git a/ipojo/runtime/changelog.txt b/ipojo/runtime/changelog.txt
new file mode 100644
index 0000000..96c9be5
--- /dev/null
+++ b/ipojo/runtime/changelog.txt
@@ -0,0 +1,223 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.10.0 to 1.10.1
+-----------------------------
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3742] - Implementing class fails to load unless super interface's (interface extended by implemented interface) package is imported.
+ * [FELIX-3789] - Deadlock due to synchronization on INSTANCE_NAME
+ * [FELIX-3819] - The export directive of iPOJO is wrong
+
+Changes from the 1.8.2 to 1.8.4
+--------------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3500] - InstanceManager concurrency issue: "A methodID cannot be associated with a method from the POJO class"
+ * [FELIX-3501] - IPojo FactoryStateListener doesn't get notified while stopping factory
+ * [FELIX-3545] - Memory leak when unregistering a component used by an aggregate dependency with an unbind callback
+ * [FELIX-3548] - Concurrent access during startup
+ * [FELIX-3567] - iPOJO Configuration Handler should not reuse the dictionary object from the configuration admin
+ * [FELIX-3576] - iPOJO fails when using constructor injection and expecting BundleContext in ctor
+ * [FELIX-3599] - Problem with 'subservice action="instantiate"' in ipojo composite
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+ * [FELIX-3672] - Potential Concurrent Modification Exception when a bundle is stopped
+
+** Improvement
+ * [FELIX-3560] - Extensions to IPojo's Factory and ComponentInstance documentation for custom handlers
+
+
+Version 1.8.2
+-------------
+ * Initial release
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/pom.xml b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/pom.xml
new file mode 100644
index 0000000..fc9bb16
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.composite-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-composite-import-export-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
new file mode 100644
index 0000000..20e2773
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class Baz2CheckProvider implements CheckService {
+
+ BazService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(fs.foo()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+ private void voidUnbind() {
+ simpleU++;
+ }
+
+ protected void objectBind(Object o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+ protected void objectUnbind(Object o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
new file mode 100644
index 0000000..5711222
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+import java.util.Properties;
+
+public class BazProviderType1 implements BazService {
+
+ private int m_bar;
+ private String m_foo;
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ p.put("foo", m_foo);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..a0e9e43
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..700d9fe
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
new file mode 100644
index 0000000..84f9e36
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Tata;
+
+import java.util.Properties;
+
+
+public class TataProvider implements Tata {
+
+ int tata = 0;
+ int tataStr = 0;
+ int tataStrs = 0;
+ int tata_2 = 0;
+ int tata_3 = 0;
+ int tata1 = 0;
+ int tata1_1 = 0;
+ int tata5 = 0;
+ int tata5_1 = 0;
+ int tata5_2 = 0;
+ int tataBoolean = 0;
+ int tataBooleans = 0;
+ int tataByte = 0;
+ int tataBytes = 0;
+ private int add;
+ private int tataShorts;
+ private int tataShort;
+ private int tataLongs;
+ private int tataLong;
+ private int tataInts;
+ private int tataInt;
+ private int tataFloat;
+ private int tataFloats;
+ private int tataDoubles;
+ private int tataDouble;
+ private int tataChars;
+ private int tataChar;
+
+ public Properties getPropsTata() {
+ Properties props = new Properties();
+ props.put("tata", new Integer(tata));
+ props.put("tataStr", new Integer(tataStr));
+ props.put("tataStrs", new Integer(tataStrs));
+ props.put("tata_2", new Integer(tata_2));
+ props.put("tata_3", new Integer(tata_3));
+ props.put("tata1", new Integer(tata1));
+ props.put("tata1_1", new Integer(tata1_1));
+ props.put("tata5", new Integer(tata5));
+ props.put("tata5_1", new Integer(tata5_1));
+ props.put("tata5_2", new Integer(tata5_2));
+ props.put("add", new Integer(add));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataByte", new Integer(tataByte));
+ props.put("tataBytes", new Integer(tataBytes));
+ props.put("tataShort", new Integer(tataShort));
+ props.put("tataShorts", new Integer(tataShorts));
+ props.put("tataLongs", new Integer(tataLongs));
+ props.put("tataLong", new Integer(tataLong));
+ props.put("tataInt", new Integer(tataInt));
+ props.put("tataInts", new Integer(tataInts));
+ props.put("tataFloat", new Integer(tataFloat));
+ props.put("tataFloats", new Integer(tataFloats));
+ props.put("tataDouble", new Integer(tataDouble));
+ props.put("tataDoubles", new Integer(tataDoubles));
+ props.put("tataChar", new Integer(tataChar));
+ props.put("tataChars", new Integer(tataChars));
+ return props;
+ }
+
+ public void tata() {
+ tata++;
+ }
+
+ public String tataStr() {
+ tataStr++;
+ return "Tata";
+ }
+
+ public String[] tataStrs() {
+ tataStrs++;
+ return new String[] {"T", "A", "T", "A"};
+ }
+
+ public void tata(int i, int j) {
+ tata_2++;
+ }
+
+ public void tata(String s) {
+ tata_3++;
+ }
+
+ public String tata1(String a) {
+ tata1++;
+ return a;
+ }
+
+ public String tata1(char[] a) {
+ tata1_1++;
+ String s = new String(a);
+ return s;
+ }
+
+ public String tata5(String a, int i) {
+ tata5++;
+ return a+i;
+ }
+
+ public String tata5(String[] a, int i) {
+ tata5_1++;
+ return ""+a.length + i;
+ }
+
+ public String tata5(String a, int[] i) {
+ tata5_2++;
+ return a + i.length;
+ }
+
+ public boolean tataBoolean(boolean b) {
+ tataBoolean++;
+ return b;
+ }
+
+ public boolean[] tataBooleans(boolean[] b) {
+ tataBooleans++;
+ return b;
+ }
+
+ public byte tataByte(byte b) {
+ tataByte++;
+ return b;
+ }
+
+ public byte[] tataBytes(byte[] b) {
+ tataBytes++;
+ return b;
+ }
+
+ public char tataChar(char c) {
+ tataChar++;
+ return c;
+ }
+
+ public char[] tataChars(char[] c) {
+ tataChars++;
+ return c;
+ }
+
+ public double tataDouble(double d) {
+ tataDouble++;
+ return d;
+ }
+
+ public double[] tataDoubles(double[] d) {
+ tataDoubles++;
+ return d;
+ }
+
+ public float tataFloat(float f) {
+ tataFloat++;
+ return f;
+ }
+
+ public float[] tataFloats(float[] f) {
+ tataFloats++;
+ return f;
+ }
+
+ public int tataInt(int i) {
+ tataInt++;
+ return i;
+ }
+
+ public int[] tataInts(int[] its) {
+ tataInts++;
+ return its;
+ }
+
+ public long tataLong(long l) {
+ tataLong++;
+ return l;
+ }
+
+ public long[] tataLongs(long[] l) {
+ tataLongs++;
+ return l;
+ }
+
+ public short tataShort(short s) {
+ tataShort++;
+ return s;
+ }
+
+ public short[] tataShorts(short[] s) {
+ tataShorts++;
+ return s;
+ }
+
+ public long add(int i, int j, int k) {
+ add++;
+ return i + j + k;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
new file mode 100644
index 0000000..5c2c033
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProvider implements Toto {
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("toto", new Integer(toto));
+ props.put("toto_2", new Integer(toto_2));
+ props.put("toto_3", new Integer(toto_3));
+ props.put("toto_4", new Integer(toto_4));
+ props.put("toto1", new Integer(toto1));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
new file mode 100644
index 0000000..dccebaf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProviderGlue implements Toto {
+
+ Toto m_toto;
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ m_toto.toto();
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ m_toto.toto(i, j);
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ m_toto.toto1(j);
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("gtoto", new Integer(toto));
+ props.put("gtoto_2", new Integer(toto_2));
+ props.put("gtoto_3", new Integer(toto_3));
+ props.put("gtoto_4", new Integer(toto_4));
+ props.put("gtoto1", new Integer(toto1));
+ props.put("glue", "glue");
+ Properties p2 = m_toto.getProps();
+ props.putAll(p2);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..5e2b59a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
new file mode 100644
index 0000000..b9cec94
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BazService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
new file mode 100644
index 0000000..a65e2dd
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
@@ -0,0 +1,62 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tata {
+
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
new file mode 100644
index 0000000..82d307c
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
@@ -0,0 +1,78 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tota {
+
+ public static final String specification="specification { " +
+ "requires { " +
+ "$specification=\"org.apache.felix.ipojo.test.composite.service.Toto\" " +
+ "$optional=\"true\" " +
+ "$aggregate=\"true\" " +
+ "$type=\"service\" " +
+ "} }";
+
+ public Properties getProps() throws UnsupportedOperationException;;
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+ public void toto() throws UnsupportedOperationException;
+ public void toto(int i, int j) throws UnsupportedOperationException;
+ public String toto(String a) throws UnsupportedOperationException;
+
+ public void toto1(String j) throws UnsupportedOperationException;
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
new file mode 100644
index 0000000..037dad3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
@@ -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.runtime.core.services;
+
+import java.util.Properties;
+
+public interface Toto {
+
+ public Properties getProps();
+
+ public void toto();
+ public void toto(int i, int j);
+ public String toto(String a);
+ public String toto(String[] a);
+
+ public void toto1(String j);
+
+ public int count();
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata-import-export.xml b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata-import-export.xml
new file mode 100644
index 0000000..26a1407
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata-import-export.xml
@@ -0,0 +1,106 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite"
+ xmlns:cs="org.apache.felix.ipojo.test.composite.handler.CheckServiceHandler">
+ <comp:composite name="composite.requires.1" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"
+ scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.requires.2" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"
+ aggregate="true" scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.requires.3" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"
+ optional="true" scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.requires.4" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"
+ optional="true" aggregate="true" scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.requires.5" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService"
+ filter="(&(int=2)(long=40))" scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.export.1" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" optional="true" filter="(!(instance.name=export))"
+ scope="composite" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService" />
+ </comp:composite>
+
+ <comp:composite name="composite.export.2" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ scope="composite" aggregate="true" optional="true"
+ filter="(!(instance.name=export))" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ optional="true" />
+ </comp:composite>
+
+ <comp:composite name="composite.export.3" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ scope="composite" aggregate="true" optional="true"
+ filter="(!(instance.name=export))" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" />
+ </comp:composite>
+
+ <comp:composite name="composite.export.4" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" optional="true" filter="(!(instance.name=export))"
+ scope="composite" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" optional="true" />
+ </comp:composite>
+
+ <comp:composite name="composite.export.5" architecture="true">
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" optional="true" filter="(!(instance.name=export))"
+ scope="composite" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ filter="(instance.name=foo1)" />
+ </comp:composite>
+
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata.xml b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..d70c60b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/main/resources/metadata.xml
@@ -0,0 +1,131 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite">
+ <!-- Used component type -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2" />
+ <property name="long" type="long" value="40" />
+ <property name="string" type="java.lang.String" value="foo" />
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" />
+ <property name="intAProp" type="int[]" value="{1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="COMPO-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="COMPO-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" />
+ <property name="boolean" field="boolProp" />
+ <property name="string" field="strProp" />
+ <property name="strAProp" field="strAProp" />
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.CheckServiceProvider"
+ name="COMPO-SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService, org.apache.felix.ipojo.runtime.core.services.BarService }" />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-3" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService}">
+ <property name="baz" type="java.lang.String" value="foo" />
+ </provides>
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.BarService}">
+ <property name="baz" type="java.lang.String" value="bar" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.BazProviderType1"
+ name="BazProviderType">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TataProvider"
+ name="tata">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProvider"
+ name="toto" architecture="true">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProviderGlue"
+ name="totoglue">
+ <requires field="m_toto" scope="composite" />
+ </component>
+
+ <!-- Composite -->
+ <comp:composite name="composite.empty" architecture="true">
+ </comp:composite>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Baz2CheckProvider" name="Baz2CheckProvider" architecture="true">
+ <requires field="fs" scope="composite"/>
+ <provides/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..13a950f
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Bootstrap the test from this project
+ */
+@ExamReactorStrategy(PerMethod.class)
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployiPOJOComposite() {
+ return true;
+ }
+
+
+ public static ServiceContext getServiceContext(ComponentInstance ci) {
+ if (ci instanceof CompositeManager) {
+ return ((CompositeManager) ci).getServiceContext();
+ } else {
+ throw new RuntimeException("Cannot get the service context from a non composite instance");
+ }
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestFilteredExport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestFilteredExport.java
new file mode 100644
index 0000000..bce5471
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestFilteredExport.java
@@ -0,0 +1,237 @@
+/*
+ * 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.exporter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestFilteredExport extends Common {
+
+ ComponentInstance export1;
+ Factory fooProvider;
+ ComponentInstance foo1 = null, foo2 = null;
+
+ @Before
+ public void setUp() {
+ fooProvider = ipojoHelper.getFactory("BazProviderType");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to create foos : " + e.getMessage());
+ }
+
+ foo1.stop();
+ foo2.stop();
+
+ Factory factory = ipojoHelper.getFactory("composite.export.5");
+ Properties props = new Properties();
+ props.put("instance.name", "export");
+ try {
+ export1 = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Fail to instantiate exporter " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ export1.dispose();
+ foo1 = null;
+ foo2 = null;
+ export1 = null;
+ }
+
+ @Test
+ public void test1() {
+ export1.start();
+
+ // Check that no foo service are available
+ assertEquals("Check no foo service", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 0);
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 3", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.stop();
+ assertTrue("Check invalidity - 4", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check invalidity - 5", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 0);
+ }
+
+ @Test
+ public void test2() {
+ export1.start();
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 4", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 5", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke());
+ }
+
+ @Test
+ public void test3() {
+ foo1.start();
+ foo2.start();
+
+ export1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 2", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 0);
+
+ foo2.stop();
+ assertTrue("Check invalidity - 3", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 4", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke());
+ }
+
+ @Test
+ public void test4() {
+ foo1.start();
+ foo2.start();
+
+ export1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 3", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check invalidity - 4", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+ }
+
+
+ private boolean isFooServiceProvided() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export1.getInstanceName());
+ return ref != null;
+ }
+
+ private int countFooServiceProvided() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export1.getInstanceName() + ")");
+ return refs.length;
+ }
+
+ private boolean invoke() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export1.getInstanceName());
+ if (ref == null) {
+ return false;
+ }
+ BazService fs = (BazService) getContext().getService(ref);
+ return fs.foo();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestMultipleExport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestMultipleExport.java
new file mode 100644
index 0000000..b9ca3a7
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestMultipleExport.java
@@ -0,0 +1,260 @@
+/*
+ * 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.exporter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMultipleExport extends Common {
+
+ ComponentInstance export3;
+ Factory fooProvider;
+ ComponentInstance foo1 = null, foo2 = null;
+
+ @Before
+ public void setUp() {
+ fooProvider = ipojoHelper.getFactory("BazProviderType");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to create foos : " + e.getMessage());
+ }
+
+ foo1.stop();
+ foo2.stop();
+
+ Factory factory = ipojoHelper.getFactory("composite.export.3");
+ Properties props = new Properties();
+ props.put("instance.name", "export");
+ try {
+ export3 = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Fail to instantiate exporter " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ export3.dispose();
+ foo1 = null;
+ foo2 = null;
+ export3 = null;
+ }
+
+ @Test
+ public void test1() {
+ export3.start();
+
+ // Check that no foo service are available
+ assertEquals("Check no foo service", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 0);
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke(1));
+
+ foo2.start();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 2", invoke(2));
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3 (" + countFooServiceProvided() + ")", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke(1));
+
+ foo2.stop();
+ assertTrue("Check invalidity - 4", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 5", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke(1));
+ }
+
+ @Test
+ public void test2() {
+ export3.start();
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 2", invoke(2));
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke(1));
+
+ foo1.stop();
+ assertTrue("Check invalidity - 4", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 5", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke(1));
+ }
+
+ @Test
+ public void test3() {
+ foo1.start();
+ foo2.start();
+
+ export3.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 1", invoke(2));
+
+ foo1.stop();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke(1));
+
+ foo2.stop();
+ assertTrue("Check invalidity - 3", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke(1));
+ }
+
+ @Test
+ public void test4() {
+ foo1.start();
+ foo2.start();
+
+ export3.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 1", invoke(2));
+
+ foo2.stop();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke(1));
+
+ foo1.stop();
+ assertTrue("Check invalidity - 3", export3.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke(1));
+ }
+
+
+ private boolean isFooServiceProvided() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export3.getInstanceName());
+ return ref != null;
+ }
+
+ private int countFooServiceProvided() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export3.getInstanceName() + ")");
+ return refs.length;
+ }
+
+ private boolean invoke() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export3.getInstanceName());
+ if (ref == null) {
+ return false;
+ }
+ BazService fs = (BazService) getContext().getService(ref);
+ getContext().ungetService(ref);
+ return fs.foo();
+ }
+
+ private boolean invoke(int nb) {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export3.getInstanceName() + ")");
+ if (refs == null) {
+ return false;
+ }
+ if (nb > refs.length) {
+ return false;
+ }
+ for (int i = 0; i < nb; i++) {
+ BazService fs = (BazService) getContext().getService(refs[i]);
+ getContext().ungetService(refs[i]);
+ if (!fs.foo()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalExport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalExport.java
new file mode 100644
index 0000000..b1716a3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalExport.java
@@ -0,0 +1,241 @@
+/*
+ * 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.exporter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalExport extends Common {
+
+ ComponentInstance export2;
+ Factory fooProvider;
+ ComponentInstance foo1 = null, foo2 = null;
+
+ @Before
+ public void setUp() {
+ fooProvider = ipojoHelper.getFactory("BazProviderType");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to create foos : " + e.getMessage());
+ }
+
+ foo1.stop();
+ foo2.stop();
+
+ Factory factory = ipojoHelper.getFactory("composite.export.2");
+ Properties props = new Properties();
+ props.put("instance.name", "export");
+ try {
+ export2 = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Fail to instantiate exporter " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ export2.dispose();
+ foo1 = null;
+ foo2 = null;
+ export2 = null;
+ }
+
+ @Test
+ public void test1() {
+ export2.start();
+
+ // Check that no foo service are available
+ assertEquals("Check no foo service", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 0);
+
+ // Test validity
+ assertTrue("Check validity - 0", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3 (" + countFooServiceProvided() + ")", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 4", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 5", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke());
+ }
+
+ @Test
+ public void test2() {
+ export2.start();
+
+ // Test invalidity
+ assertTrue("Check validity - 0", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 4", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 5", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke());
+ }
+
+ @Test
+ public void test3() {
+ foo1.start();
+ foo2.start();
+
+ export2.start();
+ assertTrue("Check validity - 1", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 2", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 4", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke());
+ }
+
+ @Test
+ public void test4() {
+ foo1.start();
+ foo2.start();
+
+ export2.start();
+ assertTrue("Check validity - 1", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 2", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export2.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 4", export2.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke());
+ }
+
+
+ private boolean isFooServiceProvided() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export2.getInstanceName());
+ return ref != null;
+ }
+
+ private int countFooServiceProvided() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export2.getInstanceName() + ")");
+ return refs.length;
+ }
+
+ private boolean invoke() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export2.getInstanceName());
+ if (ref == null) {
+ return false;
+ }
+ BazService fs = (BazService) getContext().getService(ref);
+ return fs.foo();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalMultipleExport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalMultipleExport.java
new file mode 100644
index 0000000..23afd48
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestOptionalMultipleExport.java
@@ -0,0 +1,260 @@
+/*
+ * 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.exporter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalMultipleExport extends Common {
+
+ ComponentInstance export3;
+ Factory fooProvider;
+ ComponentInstance foo1 = null, foo2 = null;
+
+ @Before
+ public void setUp() {
+ fooProvider = ipojoHelper.getFactory("BazProviderType");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to create foos : " + e.getMessage());
+ }
+
+ foo1.stop();
+ foo2.stop();
+
+ Factory factory = ipojoHelper.getFactory("composite.export.4");
+ Properties props = new Properties();
+ props.put("instance.name", "export");
+ try {
+ export3 = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Fail to instantiate exporter " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ export3.dispose();
+ foo1 = null;
+ foo2 = null;
+ export3 = null;
+ }
+
+ @Test
+ public void test1() {
+ export3.start();
+
+ // Check that no foo service are available
+ assertEquals("Check no foo service", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 0);
+
+ // Test invalidity
+ assertTrue("Check validity - 0", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke(1));
+
+ foo2.start();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 2", invoke(2));
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3 (" + countFooServiceProvided() + ")", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke(1));
+
+ foo2.stop();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 5", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke(1));
+ }
+
+ @Test
+ public void test2() {
+ export3.start();
+
+ // Test invalidity
+ assertTrue("Check validity - 0", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 2", invoke(2));
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke(1));
+
+ foo1.stop();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 5", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke(1));
+ }
+
+ @Test
+ public void test3() {
+ foo1.start();
+ foo2.start();
+
+ export3.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 1", invoke(2));
+
+ foo1.stop();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke(1));
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke(1));
+ }
+
+ @Test
+ public void test4() {
+ foo1.start();
+ foo2.start();
+
+ export3.start();
+ assertTrue("Check validity - 1", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 2);
+ assertTrue("Check invocation - 1", invoke(2));
+
+ foo2.stop();
+ assertTrue("Check validity - 2", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke(1));
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export3.getState() == ComponentInstance.VALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 4", export3.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke(1));
+ }
+
+
+ private boolean isFooServiceProvided() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export3.getInstanceName());
+ return ref != null;
+ }
+
+ private int countFooServiceProvided() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export3.getInstanceName() + ")");
+ return refs.length;
+ }
+
+ private boolean invoke() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export3.getInstanceName());
+ if (ref == null) {
+ return false;
+ }
+ BazService fs = (BazService) getContext().getService(ref);
+ getContext().ungetService(ref);
+ return fs.foo();
+ }
+
+ private boolean invoke(int nb) {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export3.getInstanceName() + ")");
+ if (refs == null) {
+ return false;
+ }
+ if (nb > refs.length) {
+ return false;
+ }
+ for (int i = 0; i < nb; i++) {
+ BazService fs = (BazService) getContext().getService(refs[i]);
+ getContext().ungetService(refs[i]);
+ if (!fs.foo()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestSimpleExport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestSimpleExport.java
new file mode 100644
index 0000000..49cad50
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/exporter/TestSimpleExport.java
@@ -0,0 +1,241 @@
+/*
+ * 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.exporter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSimpleExport extends Common {
+
+ ComponentInstance export1;
+ Factory fooProvider;
+ ComponentInstance foo1 = null, foo2 = null;
+
+ @Before
+ public void setUp() {
+ fooProvider = ipojoHelper.getFactory("BazProviderType");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to create foos : " + e.getMessage());
+ }
+
+ foo1.stop();
+ foo2.stop();
+
+ Factory factory = ipojoHelper.getFactory("composite.export.1");
+ Properties props = new Properties();
+ props.put("instance.name", "export");
+ try {
+ export1 = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Fail to instantiate exporter " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ export1.dispose();
+ foo1 = null;
+ foo2 = null;
+ export1 = null;
+ }
+
+ @Test
+ public void test1() {
+ export1.start();
+
+ // Check that no foo service are available
+ assertEquals("Check no foo service", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 0);
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 3", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3 (" + countFooServiceProvided() + ")", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke());
+
+ foo2.stop();
+ assertTrue("Check invalidity - 4", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 5", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke());
+ }
+
+ @Test
+ public void test2() {
+ export1.start();
+
+ // Test invalidity
+ assertTrue("Check invalidity - 0", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 0", isFooServiceProvided());
+ assertEquals("Check number of provides - 0", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.start();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 3", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 3", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 4", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 5", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 5", isFooServiceProvided());
+ assertEquals("Check number of provides - 5", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 5", invoke());
+ }
+
+ @Test
+ public void test3() {
+ foo1.start();
+ foo2.start();
+
+ export1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo1.stop();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo2.stop();
+ assertTrue("Check invalidity - 3", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo1.start();
+ assertTrue("Check validity - 4", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke());
+ }
+
+ @Test
+ public void test4() {
+ foo1.start();
+ foo2.start();
+
+ export1.start();
+ assertTrue("Check validity - 1", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 1", isFooServiceProvided());
+ assertEquals("Check number of provides - 1", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 1", invoke());
+
+ foo2.stop();
+ assertTrue("Check validity - 2", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 2", isFooServiceProvided());
+ assertEquals("Check number of provides - 2", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 2", invoke());
+
+ foo1.stop();
+ assertTrue("Check invalidity - 3", export1.getState() == ComponentInstance.INVALID);
+ assertFalse("Check providing - 3", isFooServiceProvided());
+ assertEquals("Check number of provides - 3", countFooServiceProvided(), 0);
+
+ foo2.start();
+ assertTrue("Check validity - 4", export1.getState() == ComponentInstance.VALID);
+ assertTrue("Check providing - 4", isFooServiceProvided());
+ assertEquals("Check number of provides - 4", countFooServiceProvided(), 1);
+ assertTrue("Check invocation - 4", invoke());
+ }
+
+
+ private boolean isFooServiceProvided() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export1.getInstanceName());
+ return ref != null;
+ }
+
+ private int countFooServiceProvided() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(BazService.class.getName(), "(instance.name=" + export1.getInstanceName() + ")");
+ return refs.length;
+ }
+
+ private boolean invoke() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), export1.getInstanceName());
+ if (ref == null) {
+ return false;
+ }
+ BazService fs = (BazService) getContext().getService(ref);
+ return fs.foo();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedFilteredImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedFilteredImport.java
new file mode 100644
index 0000000..2b4bdf7
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedFilteredImport.java
@@ -0,0 +1,157 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedFilteredImport extends Common {
+
+ ComponentInstance import1;
+ Factory fooProvider;
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.1");
+ try {
+ import1 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+
+ import1.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import1.dispose();
+ foo1 = null;
+ foo2 = null;
+ import1 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import1.start();
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo2.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ public void testSimple2() {
+ import1.start();
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo2.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedMultipleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedMultipleImport.java
new file mode 100644
index 0000000..566c26a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedMultipleImport.java
@@ -0,0 +1,163 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedMultipleImport extends Common {
+
+ ComponentInstance import2;
+ Factory fooProvider;
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.2");
+ try {
+ import2 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+
+ import2.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import2.dispose();
+ foo1 = null;
+ foo2 = null;
+ import2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import2.start();
+ //Two providers
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ fs = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation (2)", fs.foo());
+ sc.ungetService(refs[1]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component invalidity - 2", import2.getState() == ComponentInstance.INVALID);
+
+ foo2.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ public void testSimple2() {
+ import2.start();
+ //Two providers
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ fs = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[1]);
+
+ foo2.stop();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component invalidity - 2", import2.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalImport.java
new file mode 100644
index 0000000..0b3ba04
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalImport.java
@@ -0,0 +1,163 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedOptionalImport extends Common {
+
+ ComponentInstance import3;
+ Factory fooProvider;
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.3");
+ try {
+ import3 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+
+ import3.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import3.dispose();
+ foo1 = null;
+ foo2 = null;
+ import3 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import3.start();
+ //Two providers
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import3);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component validity - 2", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo non-availability inside the composite - 3.1", refs.length, 0);
+
+ foo2.start();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ public void testSimple2() {
+ import3.start();
+ //Two providers
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import3);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo2.stop();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component validity - 2", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 0);
+
+ foo1.start();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalMultipleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalMultipleImport.java
new file mode 100644
index 0000000..13c953b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedOptionalMultipleImport.java
@@ -0,0 +1,169 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedOptionalMultipleImport extends Common {
+
+ ComponentInstance import4;
+ Factory fooProvider;
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.4");
+ try {
+ import4 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+
+ import4.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import4.dispose();
+ foo1 = null;
+ foo2 = null;
+ import4 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import4.start();
+ //Two providers
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import4);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ fs = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation (2)", fs.foo());
+ sc.ungetService(refs[1]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component validity - 2", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo availability inside the composite - 1", refs.length, 0);
+
+ foo2.start();
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ public void testSimple2() {
+ import4.start();
+ //Two providers
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import4);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ fs = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[1]);
+
+ foo2.stop();
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component validity - 2", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo availability inside the composite - 1", refs.length, 0);
+
+ foo1.start();
+ assertTrue("Test component validity", import4.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import4);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedSimpleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedSimpleImport.java
new file mode 100644
index 0000000..262de1b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestDelayedSimpleImport.java
@@ -0,0 +1,158 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedSimpleImport extends Common {
+
+ ComponentInstance import1;
+ Factory fooProvider;
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.1");
+ try {
+ import1 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+
+ import1.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import1.dispose();
+ foo1 = null;
+ foo2 = null;
+ import1 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import1.start();
+
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo2.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ public void testSimple2() {
+ import1.start();
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo2.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestFilteredImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestFilteredImport.java
new file mode 100644
index 0000000..174e0ad
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestFilteredImport.java
@@ -0,0 +1,157 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestFilteredImport extends Common {
+
+ ComponentInstance import1;
+ Factory fooProvider;
+ Factory fooProvider2;
+
+ ComponentInstance foo1, foo2;
+
+ @Before
+ public void setUp() {
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.5");
+ try {
+ import1 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+ import1.stop();
+
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ fooProvider2 = ipojoHelper.getFactory("COMPO-FooProviderType-2");
+ assertNotNull("Check fooProvider availability", fooProvider2);
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "foo1");
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo1 = fooProvider.createComponentInstance(p1);
+ foo2 = fooProvider2.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ foo1.dispose();
+ foo2.dispose();
+ import1.dispose();
+ foo1 = null;
+ foo2 = null;
+ import1 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ import1.start();
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo2.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+ @Test
+ @Ignore("known as broken after interception inception in service dependencies")
+ public void testSimple2() {
+ import1.start();
+ //Two providers
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo2.stop();
+ assertTrue("Test component invalidity - 1", import1.getState() == ComponentInstance.INVALID);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component invalidity - 3", import1.getState() == ComponentInstance.INVALID);
+
+ foo2.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestMultipleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestMultipleImport.java
new file mode 100644
index 0000000..7cdb91a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestMultipleImport.java
@@ -0,0 +1,199 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMultipleImport extends Common {
+
+ ComponentInstance import2;
+ Factory fooProvider;
+
+ @Before
+ public void setUp() {
+ osgiHelper.waitForService(Factory.class, "(factory.name=COMPO-FooProviderType-1)", 1000);
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.2");
+ try {
+ import2 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ import2.dispose();
+ import2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ // No provider -> Invalid
+ assertTrue("Test component invalidity", import2.getState() == ComponentInstance.INVALID);
+
+ ComponentInstance foo = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2 (" + refs.length + ")", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ FooService fs2 = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs2.foo());
+ sc.ungetService(refs[0]);
+ sc.ungetService(refs[1]);
+
+ // Stop the second provider
+ foo2.dispose();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the foo provider
+ foo.stop();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import2.getState() == ComponentInstance.INVALID);
+
+ foo.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import2.getState() == ComponentInstance.INVALID);
+ }
+
+ @Test
+ public void testSimple2() {
+ // No provider -> Invalid
+ assertTrue("Test component invalidity", import2.getState() == ComponentInstance.INVALID);
+
+ ComponentInstance foo1 = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo1 = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2 (" + refs.length + ")", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ FooService fs2 = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs2.foo());
+ sc.ungetService(refs[0]);
+ sc.ungetService(refs[1]);
+
+ // Stop the first provider
+ foo1.stop();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the second foo provider
+ foo2.dispose();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import2.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import2.getState() == ComponentInstance.INVALID);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalImport.java
new file mode 100644
index 0000000..3d7d351
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalImport.java
@@ -0,0 +1,193 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalImport extends Common {
+
+ ComponentInstance import3;
+ Factory fooProvider;
+
+ @Before
+ public void setUp() {
+ osgiHelper.waitForService(Factory.class, "(factory.name=COMPO-FooProviderType-1)", 1000);
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.3");
+ try {
+ import3 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ import3.dispose();
+ import3 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ // No provider -> valid
+ assertTrue("Test component invalidity", import3.getState() == ComponentInstance.VALID);
+
+ ComponentInstance foo = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import3);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.dispose();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the foo provider
+ foo.stop();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import3.getState() == ComponentInstance.VALID);
+
+ foo.start();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import3.getState() == ComponentInstance.VALID);
+ }
+
+ @Test
+ public void testSimple2() {
+ // No provider -> valid
+ assertTrue("Test component invalidity", import3.getState() == ComponentInstance.VALID);
+
+ ComponentInstance foo1 = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo1 = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import3);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo1.stop();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the foo provider
+ foo2.dispose();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import3.getState() == ComponentInstance.VALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import3.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import3);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import3.getState() == ComponentInstance.VALID);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalMultipleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalMultipleImport.java
new file mode 100644
index 0000000..d5259d8
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestOptionalMultipleImport.java
@@ -0,0 +1,210 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalMultipleImport extends Common {
+
+ ComponentInstance import2;
+ Factory fooProvider;
+
+ @Before
+ public void setUp() {
+ osgiHelper.waitForService(Factory.class, "(factory.name=COMPO-FooProviderType-1)", 1000);
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.4");
+ try {
+ import2 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ import2.dispose();
+ import2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ // No provider -> valid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+
+ ComponentInstance foo = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2 (" + refs.length + ")", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ FooService fs2 = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs2.foo());
+ sc.ungetService(refs[0]);
+ sc.ungetService(refs[1]);
+
+ // Stop the second provider
+ foo2.dispose();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the foo provider
+ foo.stop();
+
+ // No provider -> valid
+ assertTrue("Test component validity - 2", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo non-availability inside the composite - 1", refs.length, 0);
+
+ foo.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component validity - 3", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo non-availability inside the composite - 2", refs.length, 0);
+ }
+
+ @Test
+ public void testSimple2() {
+ // No provider -> Invalid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+
+ ComponentInstance foo1 = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo1 = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import2);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2 (" + refs.length + ")", refs.length, 2);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ FooService fs2 = (FooService) sc.getService(refs[1]);
+ assertTrue("Test foo invocation", fs2.foo());
+ sc.ungetService(refs[0]);
+ sc.ungetService(refs[1]);
+
+ // Stop the first provider
+ foo1.stop();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the second foo provider
+ foo2.dispose();
+
+ // No provider -> Invalid
+ assertTrue("Test component validity - 2", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo non-availability inside the composite - 1", refs.length, 0);
+
+ foo1.start();
+ assertTrue("Test component validity", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import2.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import2);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertEquals("Test foo non-availability inside the composite - 2", refs.length, 0);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestSimpleImport.java b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestSimpleImport.java
new file mode 100644
index 0000000..c97965a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-import-export-test/src/test/java/org/apache/felix/ipojo/runtime/core/importer/TestSimpleImport.java
@@ -0,0 +1,193 @@
+/*
+ * 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.importer;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSimpleImport extends Common {
+
+ ComponentInstance import1;
+ Factory fooProvider;
+
+ @Before
+ public void setUp() {
+ osgiHelper.waitForService(Factory.class, "(factory.name=COMPO-FooProviderType-1)", 1000);
+ fooProvider = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ assertNotNull("Check fooProvider availability", fooProvider);
+
+ Properties p = new Properties();
+ p.put("instance.name", "importer");
+ Factory compFact = ipojoHelper.getFactory("composite.requires.1");
+ try {
+ import1 = compFact.createComponentInstance(p);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate the component : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ import1.dispose();
+ import1 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 0 (" + import1.getState() + ")", import1.getState() == ComponentInstance.INVALID);
+
+ ComponentInstance foo = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity - 1", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the second provider
+ foo2.dispose();
+ assertTrue("Test component validity - 2", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the foo provider
+ foo.stop();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo.start();
+ assertTrue("Test component validity - 3", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import1.getState() == ComponentInstance.INVALID);
+ }
+
+ @Test
+ public void testSimple2() {
+ // No provider -> Invalid
+ assertTrue("Test component invalidity", import1.getState() == ComponentInstance.INVALID);
+
+ ComponentInstance foo1 = null;
+ Properties p = new Properties();
+ p.put("instance.name", "foo");
+ try {
+ foo1 = fooProvider.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo component " + e.getMessage());
+ }
+
+ ComponentInstance foo2 = null;
+ Properties p2 = new Properties();
+ p2.put("instance.name", "foo2");
+ try {
+ foo2 = fooProvider.createComponentInstance(p2);
+ } catch (Exception e) {
+ fail("Fail to instantiate the foo2 component " + e.getMessage());
+ }
+
+ // The foo service is available => import1 must be valid
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(import1);
+ ServiceReference[] refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 1", refs);
+ assertEquals("Test foo availability inside the composite - 1.2", refs.length, 1);
+ FooService fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // Stop the first provider
+ foo1.stop();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 2", refs);
+ assertEquals("Test foo availability inside the composite - 2.1 (" + refs.length + ")", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ // stop the second foo provider
+ foo2.dispose();
+
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 2", import1.getState() == ComponentInstance.INVALID);
+
+ foo1.start();
+ assertTrue("Test component validity", import1.getState() == ComponentInstance.VALID);
+ sc = getServiceContext(import1);
+ refs = ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null);
+ assertNotNull("Test foo availability inside the composite - 3", refs);
+ assertEquals("Test foo availability inside the composite - 3.1", refs.length, 1);
+ fs = (FooService) sc.getService(refs[0]);
+ assertTrue("Test foo invocation", fs.foo());
+ sc.ungetService(refs[0]);
+
+ foo1.dispose();
+ // No provider -> Invalid
+ assertTrue("Test component invalidity - 3", import1.getState() == ComponentInstance.INVALID);
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/pom.xml b/ipojo/runtime/composite-it/ipojo-composite-instance-test/pom.xml
new file mode 100644
index 0000000..dfb1da4
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.composite-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-composite-instance-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
new file mode 100644
index 0000000..20e2773
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class Baz2CheckProvider implements CheckService {
+
+ BazService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(fs.foo()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+ private void voidUnbind() {
+ simpleU++;
+ }
+
+ protected void objectBind(Object o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+ protected void objectUnbind(Object o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
new file mode 100644
index 0000000..5711222
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+import java.util.Properties;
+
+public class BazProviderType1 implements BazService {
+
+ private int m_bar;
+ private String m_foo;
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ p.put("foo", m_foo);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..a0e9e43
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..700d9fe
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java
new file mode 100644
index 0000000..f772059
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.Service;
+
+import java.util.Properties;
+
+public class ServiceConsumer implements CheckService {
+
+ private Service service;
+ private Properties props = new Properties();
+
+ public ServiceConsumer() {
+ props.put("1", new Integer(service.count()));
+ props.put("2", new Integer(service.count()));
+ props.put("3", new Integer(service.count()));
+ }
+
+ public boolean check() {
+ return service.count() > 0;
+ }
+
+ public Properties getProps() {
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java
new file mode 100644
index 0000000..9c2f212
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Service;
+
+
+public class ServiceProvider implements Service {
+
+ private int i = 0;
+
+ public int count() {
+ i++;
+ return i;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
new file mode 100644
index 0000000..84f9e36
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Tata;
+
+import java.util.Properties;
+
+
+public class TataProvider implements Tata {
+
+ int tata = 0;
+ int tataStr = 0;
+ int tataStrs = 0;
+ int tata_2 = 0;
+ int tata_3 = 0;
+ int tata1 = 0;
+ int tata1_1 = 0;
+ int tata5 = 0;
+ int tata5_1 = 0;
+ int tata5_2 = 0;
+ int tataBoolean = 0;
+ int tataBooleans = 0;
+ int tataByte = 0;
+ int tataBytes = 0;
+ private int add;
+ private int tataShorts;
+ private int tataShort;
+ private int tataLongs;
+ private int tataLong;
+ private int tataInts;
+ private int tataInt;
+ private int tataFloat;
+ private int tataFloats;
+ private int tataDoubles;
+ private int tataDouble;
+ private int tataChars;
+ private int tataChar;
+
+ public Properties getPropsTata() {
+ Properties props = new Properties();
+ props.put("tata", new Integer(tata));
+ props.put("tataStr", new Integer(tataStr));
+ props.put("tataStrs", new Integer(tataStrs));
+ props.put("tata_2", new Integer(tata_2));
+ props.put("tata_3", new Integer(tata_3));
+ props.put("tata1", new Integer(tata1));
+ props.put("tata1_1", new Integer(tata1_1));
+ props.put("tata5", new Integer(tata5));
+ props.put("tata5_1", new Integer(tata5_1));
+ props.put("tata5_2", new Integer(tata5_2));
+ props.put("add", new Integer(add));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataByte", new Integer(tataByte));
+ props.put("tataBytes", new Integer(tataBytes));
+ props.put("tataShort", new Integer(tataShort));
+ props.put("tataShorts", new Integer(tataShorts));
+ props.put("tataLongs", new Integer(tataLongs));
+ props.put("tataLong", new Integer(tataLong));
+ props.put("tataInt", new Integer(tataInt));
+ props.put("tataInts", new Integer(tataInts));
+ props.put("tataFloat", new Integer(tataFloat));
+ props.put("tataFloats", new Integer(tataFloats));
+ props.put("tataDouble", new Integer(tataDouble));
+ props.put("tataDoubles", new Integer(tataDoubles));
+ props.put("tataChar", new Integer(tataChar));
+ props.put("tataChars", new Integer(tataChars));
+ return props;
+ }
+
+ public void tata() {
+ tata++;
+ }
+
+ public String tataStr() {
+ tataStr++;
+ return "Tata";
+ }
+
+ public String[] tataStrs() {
+ tataStrs++;
+ return new String[] {"T", "A", "T", "A"};
+ }
+
+ public void tata(int i, int j) {
+ tata_2++;
+ }
+
+ public void tata(String s) {
+ tata_3++;
+ }
+
+ public String tata1(String a) {
+ tata1++;
+ return a;
+ }
+
+ public String tata1(char[] a) {
+ tata1_1++;
+ String s = new String(a);
+ return s;
+ }
+
+ public String tata5(String a, int i) {
+ tata5++;
+ return a+i;
+ }
+
+ public String tata5(String[] a, int i) {
+ tata5_1++;
+ return ""+a.length + i;
+ }
+
+ public String tata5(String a, int[] i) {
+ tata5_2++;
+ return a + i.length;
+ }
+
+ public boolean tataBoolean(boolean b) {
+ tataBoolean++;
+ return b;
+ }
+
+ public boolean[] tataBooleans(boolean[] b) {
+ tataBooleans++;
+ return b;
+ }
+
+ public byte tataByte(byte b) {
+ tataByte++;
+ return b;
+ }
+
+ public byte[] tataBytes(byte[] b) {
+ tataBytes++;
+ return b;
+ }
+
+ public char tataChar(char c) {
+ tataChar++;
+ return c;
+ }
+
+ public char[] tataChars(char[] c) {
+ tataChars++;
+ return c;
+ }
+
+ public double tataDouble(double d) {
+ tataDouble++;
+ return d;
+ }
+
+ public double[] tataDoubles(double[] d) {
+ tataDoubles++;
+ return d;
+ }
+
+ public float tataFloat(float f) {
+ tataFloat++;
+ return f;
+ }
+
+ public float[] tataFloats(float[] f) {
+ tataFloats++;
+ return f;
+ }
+
+ public int tataInt(int i) {
+ tataInt++;
+ return i;
+ }
+
+ public int[] tataInts(int[] its) {
+ tataInts++;
+ return its;
+ }
+
+ public long tataLong(long l) {
+ tataLong++;
+ return l;
+ }
+
+ public long[] tataLongs(long[] l) {
+ tataLongs++;
+ return l;
+ }
+
+ public short tataShort(short s) {
+ tataShort++;
+ return s;
+ }
+
+ public short[] tataShorts(short[] s) {
+ tataShorts++;
+ return s;
+ }
+
+ public long add(int i, int j, int k) {
+ add++;
+ return i + j + k;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
new file mode 100644
index 0000000..5c2c033
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProvider implements Toto {
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("toto", new Integer(toto));
+ props.put("toto_2", new Integer(toto_2));
+ props.put("toto_3", new Integer(toto_3));
+ props.put("toto_4", new Integer(toto_4));
+ props.put("toto1", new Integer(toto1));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
new file mode 100644
index 0000000..dccebaf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProviderGlue implements Toto {
+
+ Toto m_toto;
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ m_toto.toto();
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ m_toto.toto(i, j);
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ m_toto.toto1(j);
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("gtoto", new Integer(toto));
+ props.put("gtoto_2", new Integer(toto_2));
+ props.put("gtoto_3", new Integer(toto_3));
+ props.put("gtoto_4", new Integer(toto_4));
+ props.put("gtoto1", new Integer(toto1));
+ props.put("glue", "glue");
+ Properties p2 = m_toto.getProps();
+ props.putAll(p2);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..5e2b59a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
new file mode 100644
index 0000000..b9cec94
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BazService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java
new file mode 100644
index 0000000..6ef60bf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface Service {
+
+ public int count();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
new file mode 100644
index 0000000..a65e2dd
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
@@ -0,0 +1,62 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tata {
+
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
new file mode 100644
index 0000000..82d307c
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
@@ -0,0 +1,78 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tota {
+
+ public static final String specification="specification { " +
+ "requires { " +
+ "$specification=\"org.apache.felix.ipojo.test.composite.service.Toto\" " +
+ "$optional=\"true\" " +
+ "$aggregate=\"true\" " +
+ "$type=\"service\" " +
+ "} }";
+
+ public Properties getProps() throws UnsupportedOperationException;;
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+ public void toto() throws UnsupportedOperationException;
+ public void toto(int i, int j) throws UnsupportedOperationException;
+ public String toto(String a) throws UnsupportedOperationException;
+
+ public void toto1(String j) throws UnsupportedOperationException;
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
new file mode 100644
index 0000000..037dad3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
@@ -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.runtime.core.services;
+
+import java.util.Properties;
+
+public interface Toto {
+
+ public Properties getProps();
+
+ public void toto();
+ public void toto(int i, int j);
+ public String toto(String a);
+ public String toto(String[] a);
+
+ public void toto1(String j);
+
+ public int count();
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata-instance.xml b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata-instance.xml
new file mode 100644
index 0000000..90131d8
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata-instance.xml
@@ -0,0 +1,108 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite"
+ xmlns:cs="org.apache.felix.ipojo.test.composite.handler.CheckServiceHandler">
+ <comp:composite name="composite.bar.1" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.BarService"/>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.2" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.BarService" aggregate="true"/>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.3" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.BarService" optional="true"/>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.4" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.FooService" aggregate="true" optional="true"/>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.5-accept" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <property name="boolean" value="true"/>
+ <property name="string" value="foo"/>
+ <property name="strAprop" value="{foo, bar, baz}"/>
+ <property name="int" value="5"/>
+ </subservice>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.5-refuse1" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.BarService">
+ <property name="foo" value="bar"/>
+ <property name="boolean" value="true"/>
+ <property name="string" value="foo"/>
+ <property name="strAprop" value="{foo, bar, baz}"/>
+ <property name="int" value="5"/>
+ </subservice>
+ </comp:composite>
+
+ <comp:composite name="composite.bar.5-refuse2" architecture="true">
+ <subservice action="instantiate" specification="org.apache.felix.ipojo.runtime.core.services.BarService">
+ <property name="string" value="foo"/>
+ <property name="strAprop" value="{foo, bar, baz}"/>
+ </subservice>
+ </comp:composite>
+
+ <!-- Instance of a specified component -->
+ <comp:composite name="composite.inst.1" architecture="true">
+ <instance component="COMPO-FooProviderType-1" /> <!-- name="FooProv" -->
+ <instance component="COMPO-FooProviderType-Dyn2">
+ <property name="boolean" value="true"/>
+ <property name="string" value="foo"/>
+ <property name="strAProp" value="{a,b,c}"/>
+ </instance>
+ </comp:composite>
+
+ <!-- Scope test -->
+ <component name="SCOPE-provider" classname="org.apache.felix.ipojo.runtime.core.components.ServiceProvider">
+ <provides/>
+ </component>
+ <component name="SCOPE-cons" classname="org.apache.felix.ipojo.runtime.core.components.ServiceConsumer">
+ <provides/>
+ <requires field="service"/>
+ </component>
+ <comp:composite name="SCOPE-scope">
+ <instance component="SCOPE-provider"/>
+ <instance component="SCOPE-cons"/>
+ </comp:composite>
+ <comp:composite name="SCOPE-badscope">
+ <instance component="SCOPE-cons"/>
+ </comp:composite>
+
+ <!-- Instance configuration -->
+ <comp:composite name="CONF-MySuperComposite">
+ <instance component="COMPO-FooProviderType-2">
+ <property name="int" value="3"/>
+ </instance>
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <property name="boolean" value="true"/>
+ <property name="string" value="foo"/>
+ <property name="strAprop" value="{foo, bar, baz}"/>
+ <property name="int" value="3"/>
+ </subservice>
+ </comp:composite>
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata.xml b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..d70c60b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/main/resources/metadata.xml
@@ -0,0 +1,131 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite">
+ <!-- Used component type -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2" />
+ <property name="long" type="long" value="40" />
+ <property name="string" type="java.lang.String" value="foo" />
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" />
+ <property name="intAProp" type="int[]" value="{1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="COMPO-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="COMPO-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" />
+ <property name="boolean" field="boolProp" />
+ <property name="string" field="strProp" />
+ <property name="strAProp" field="strAProp" />
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.CheckServiceProvider"
+ name="COMPO-SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService, org.apache.felix.ipojo.runtime.core.services.BarService }" />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-3" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService}">
+ <property name="baz" type="java.lang.String" value="foo" />
+ </provides>
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.BarService}">
+ <property name="baz" type="java.lang.String" value="bar" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.BazProviderType1"
+ name="BazProviderType">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TataProvider"
+ name="tata">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProvider"
+ name="toto" architecture="true">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProviderGlue"
+ name="totoglue">
+ <requires field="m_toto" scope="composite" />
+ </component>
+
+ <!-- Composite -->
+ <comp:composite name="composite.empty" architecture="true">
+ </comp:composite>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Baz2CheckProvider" name="Baz2CheckProvider" architecture="true">
+ <requires field="fs" scope="composite"/>
+ <provides/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..b0bf76b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+@ExamReactorStrategy(PerMethod.class)
+public class Common extends BaseTest {
+
+ public static ServiceContext getServiceContext(ComponentInstance ci) {
+ if (ci instanceof CompositeManager) {
+ return ((CompositeManager) ci).getServiceContext();
+ } else {
+ throw new RuntimeException("Cannot get the service context from a non composite instance");
+ }
+ }
+
+ @Override
+ public boolean deployiPOJOComposite() {
+ return true;
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestInstanceScope.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestInstanceScope.java
new file mode 100644
index 0000000..f9e09ba
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestInstanceScope.java
@@ -0,0 +1,105 @@
+/*
+ * 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.instance;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.composite.CompositeFactory;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.Service;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestInstanceScope extends Common {
+
+ CompositeFactory factory;
+ ComponentInstance instance;
+
+ @Before
+ public void setUp() {
+ factory = (CompositeFactory) ipojoHelper.getFactory("SCOPE-scope");
+ assertNotNull("Factory", factory);
+ try {
+ instance = factory.createComponentInstance(null);
+ } catch (Exception e) {
+ fail("Fail instantiation : " + e.getMessage());
+ }
+
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance = null;
+ }
+
+ @Test
+ public void testScope() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance.getInstanceName());
+ assertNotNull("Check architecture availability", ref);
+ Architecture arch = (Architecture) getContext().getService(ref);
+ assertTrue("Validity", arch.getInstanceDescription().getState() == ComponentInstance.VALID);
+
+ // Get internal service
+ ServiceContext sc = getServiceContext(instance);
+ ServiceReference ref2 = ipojoHelper.getServiceReference(sc, CheckService.class.getName(), null);
+ assertNotNull("Check CheckService availability", ref2);
+ CheckService svc = (CheckService) sc.getService(ref2);
+ Properties props = svc.getProps();
+ assertEquals("Check props - 1", 1, ((Integer) props.get("1")).intValue());
+ assertEquals("Check props - 2", 2, ((Integer) props.get("2")).intValue());
+ assertEquals("Check props - 3", 3, ((Integer) props.get("3")).intValue());
+
+ }
+
+ @Test
+ public void testGlobalUnavailability() {
+ ServiceReference ref2 = osgiHelper.getServiceReference(Service.class.getName(), null);
+ assertNull("Check Service unavailability", ref2);
+ }
+
+ @Test
+ public void testScopeUnvailability() {
+ CompositeFactory factory2 = (CompositeFactory) ipojoHelper.getFactory("SCOPE-badscope");
+ assertNotNull("Factory", factory2);
+ ComponentInstance instance2 = null;
+ try {
+ instance2 = factory2.createComponentInstance(null);
+ } catch (Exception e) {
+ fail("Fail instantiation : " + e.getMessage());
+ }
+ //System.out.println(instance2.getInstanceDescription().getDescription());
+
+ assertEquals("Check invalidity", ComponentInstance.INVALID, instance2.getState());
+ instance2.dispose();
+
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestSimpleInstance.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestSimpleInstance.java
new file mode 100644
index 0000000..d145404
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instance/TestSimpleInstance.java
@@ -0,0 +1,279 @@
+/*
+ * 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.instance;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestSimpleInstance extends Common {
+
+ private ComponentFactory fooFactory1, fooFactory2;
+ private ComponentFactory compoFactory;
+ private ComponentInstance empty;
+
+ @Before
+ public void setUp() {
+ fooFactory1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ fooFactory2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooProviderType-Dyn2");
+ compoFactory = (ComponentFactory) ipojoHelper.getFactory("composite.inst.1");
+ Factory fact = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty-X");
+ try {
+ empty = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the empty composite : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testCreation() {
+ Properties props = new Properties();
+ props.put("instance.name", "under-A");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate under from " + compoFactory.getName() + " -> " + e.getMessage());
+ }
+
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailability() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+
+ assertNotNull("Check service availability", sc.getServiceReference(FooService.class.getName()));
+ assertEquals("Check service provider", ipojoHelper.getServiceReferences(sc, FooService.class.getName(), null).length,
+ 2);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testCreationLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailabilityLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under-X");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+
+ assertNotNull("Check service availability", sc2.getServiceReference(FooService.class.getName()));
+ assertEquals("Check service providers", ipojoHelper.getServiceReferences(sc2, FooService.class.getName(),
+ null).length, 2);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testFactoryManagement() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ fooFactory1.stop();
+ assertTrue("Check instance invalidity - 2", under.getState() == ComponentInstance.INVALID);
+
+ fooFactory1.start();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fooFactory2.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+
+ fooFactory2.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fooFactory1.start();
+ fooFactory2.start();
+ }
+
+ @Test
+ public void testFactoryManagementLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ fooFactory1.stop();
+ assertTrue("Check instance invalidity - 2", under.getState() == ComponentInstance.INVALID);
+
+ fooFactory1.start();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fooFactory2.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+
+ fooFactory2.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fooFactory1.start();
+ fooFactory2.start();
+ }
+
+ public void atestArchitecture() { // TODO fix and reactivate the method.
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ ServiceReference ref = osgiHelper.getServiceReference(Architecture.class.getName(),
+ "(architecture.instance=under)");
+ assertNotNull("Check architecture availability", ref);
+ Architecture arch = (Architecture) getContext().getService(ref);
+ CompositeInstanceDescription id = (CompositeInstanceDescription) arch.getInstanceDescription();
+
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ InstanceDescription[] contained = id.getContainedInstances();
+ assertEquals("Check contained instances count (" + contained.length + ")", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ ref = osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=under)");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.INVALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 0);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfigurableInstantiation.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfigurableInstantiation.java
new file mode 100644
index 0000000..a2411a1
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfigurableInstantiation.java
@@ -0,0 +1,112 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestConfigurableInstantiation extends Common {
+
+ private ComponentFactory acceptF;
+ private ComponentFactory refuse1F;
+ private ComponentFactory refuse2F;
+
+ @Before
+ public void setUp() {
+ acceptF = (ComponentFactory) ipojoHelper.getFactory("composite.bar.5-accept");
+ refuse1F = (ComponentFactory) ipojoHelper.getFactory("composite.bar.5-refuse1");
+ refuse2F = (ComponentFactory) ipojoHelper.getFactory("composite.bar.5-refuse2");
+
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testAccept() {
+ Properties props = new Properties();
+ props.put("instance.name", "under-A");
+ ComponentInstance under = null;
+ try {
+ under = acceptF.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ ServiceReference ref = sc.getServiceReference(FooService.class.getName());
+ assertNotNull("Check refs not null", ref);
+ FooService foo = (FooService) sc.getService(ref);
+ Properties p = foo.fooProps();
+ boolean b = ((Boolean) p.get("boolProp")).booleanValue();
+ String s = (String) p.get("strProp");
+ int i = ((Integer) p.get("intProp")).intValue();
+ assertTrue("Test boolean", b);
+ assertEquals("Test string", s, "foo");
+ //TODO See why it fails...
+ //assertEquals("Test int", i, 5); // The code fix to 5.
+ under.dispose();
+ }
+
+ @Test
+ public void testRefuse1() {
+ Properties props = new Properties();
+ props.put("instance.name", "under-ref1");
+ ComponentInstance under = null;
+ try {
+ under = refuse1F.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+
+ assertTrue("Check that under is not valid", under.getState() == ComponentInstance.INVALID);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testRefuse2() {
+ Properties props = new Properties();
+ props.put("instance.name", "under-ref2");
+ ComponentInstance under = null;
+ try {
+ under = refuse2F.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+
+ assertTrue("Check that under is not valid", under.getState() == ComponentInstance.INVALID);
+
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfiguration.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfiguration.java
new file mode 100644
index 0000000..a2be2c0
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestConfiguration.java
@@ -0,0 +1,98 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestConfiguration extends Common {
+
+ private ComponentFactory compositeFactory;
+
+ @Before
+ public void setUp() {
+ compositeFactory = (ComponentFactory) ipojoHelper.getFactory("CONF-MySuperComposite");
+ }
+
+ @After
+ public void tearDown() {
+
+ }
+
+ @Test
+ public void testDefaultInstantiation() throws InvalidSyntaxException {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = compositeFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ ServiceReference[] refs = sc.getServiceReferences(FooService.class.getName(), null);
+ assertEquals(2, refs.length);
+ for (int i = 0; i < refs.length; i++) {
+ assertEquals(3, ((Integer) refs[i].getProperty("int")).intValue());
+ assertEquals("foo", (String) refs[i].getProperty("string"));
+ }
+ under.dispose();
+ }
+
+ @Test
+ public void testConfiguredInstantiation() throws InvalidSyntaxException {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ props.put("string", "bar");
+ props.put("int", "25");
+ ComponentInstance under = null;
+ try {
+ under = compositeFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ ServiceReference[] refs = sc.getServiceReferences(FooService.class.getName(), null);
+ assertEquals(2, refs.length);
+ for (int i = 0; i < refs.length; i++) {
+ assertEquals(25, ((Integer) refs[i].getProperty("int")).intValue());
+ assertEquals("bar", (String) refs[i].getProperty("string"));
+ }
+ under.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestMultipleInstantiation.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestMultipleInstantiation.java
new file mode 100644
index 0000000..3aa511f
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestMultipleInstantiation.java
@@ -0,0 +1,287 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMultipleInstantiation extends Common {
+
+ private ComponentFactory bar2Factory;
+ private ComponentInstance empty;
+
+ @Before
+ public void setUp() {
+ bar2Factory = (ComponentFactory) ipojoHelper.getFactory("composite.bar.2");
+ Factory fact = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+ try {
+ empty = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the empty composite : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testCreation() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailability() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ assertNotNull("Check service availability", sc.getServiceReference(BarService.class.getName()));
+ int count = ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length;
+ assertEquals("Check service provider number : " + count, count, 3);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testCreationLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailabilityLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+ assertNotNull("Check service availability", sc2.getServiceReference(BarService.class.getName()));
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2, BarService.class.getName(), null).length, 3);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testFactoryManagement() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ ServiceContext sc = getServiceContext(under);
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length, 2);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length, 1);
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length, 0);
+
+ fact1.start();
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length, 1);
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test
+ public void testFactoryManagementLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2, BarService.class.getName(), null).length, 2);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2, BarService.class.getName(), null).length, 1);
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2, BarService.class.getName(), null).length, 0);
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2, BarService.class.getName(), null).length, 1);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test
+ public void testArchitecture() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ Architecture arch = (Architecture) getContext().getService(ref);
+ CompositeInstanceDescription id = (CompositeInstanceDescription) arch.getInstanceDescription();
+
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ InstanceDescription[] contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 3);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.2");
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 2);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.2");
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.2");
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.INVALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 0);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.2");
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.2");
+
+ getContext().ungetService(ref);
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalInstantiation.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalInstantiation.java
new file mode 100644
index 0000000..667d724
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalInstantiation.java
@@ -0,0 +1,273 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalInstantiation extends Common {
+
+ private ComponentFactory bar1Factory;
+ private ComponentInstance empty;
+
+ @Before
+ public void setUp() {
+ bar1Factory = (ComponentFactory) ipojoHelper.getFactory("composite.bar.3");
+ Factory fact = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name","empty");
+ try {
+ empty = fact.createComponentInstance(props);
+ } catch(Exception e) {
+ fail("Cannot create the empty composite : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testCreation() {
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test public void testServiceAvailability() {
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ assertNotNull("Check service availability", sc.getServiceReference(BarService.class.getName()));
+
+ under.dispose();
+ }
+
+ @Test public void testCreationLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test public void testServiceAvailabilityLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+ assertNotNull("Check service availability", sc2.getServiceReference(BarService.class.getName()));
+
+ under.dispose();
+ }
+
+ @Test public void testFactoryManagement() {
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fact3.stop();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ assertNull("Check that no Bar Service is available", sc.getServiceReference(BarService.class.getName()));
+
+ fact1.start();
+ assertTrue("Check instance validity - 5", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test public void testFactoryManagementLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fact3.stop();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ fact1.start();
+ assertTrue("Check instance validity - 5", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test public void testArchitecture() {
+ Properties props = new Properties();
+ props.put("instance.name","under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch(Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ Architecture arch = (Architecture) getContext().getService(ref);
+ assertNotNull("Check architecture", arch);
+ CompositeInstanceDescription id = (CompositeInstanceDescription) arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ InstanceDescription[] contained = id.getContainedInstances();
+ assertNotNull("Check contained not null", contained);
+ assertEquals("Check contained instances count ("+contained.length+") - 1", contained.length, 1);
+ assertEquals("Check instance name" , id.getName(), "under");
+ assertEquals("Check component type name" , id.getComponentDescription().getName(), "composite.bar.3");
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name" , id.getName(), "under");
+ assertEquals("Check component type name" , id.getComponentDescription().getName(), "composite.bar.3");
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name" , id.getName(), "under");
+ assertEquals("Check component type name" , id.getComponentDescription().getName(), "composite.bar.3");
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 0);
+ assertEquals("Check instance name" , id.getName(), "under");
+ assertEquals("Check component type name" , id.getComponentDescription().getName(), "composite.bar.3");
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name" , id.getName(), "under");
+ assertEquals("Check component type name" , id.getComponentDescription().getName(), "composite.bar.3");
+
+ getContext().ungetService(ref);
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalMultipleInstantiation.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalMultipleInstantiation.java
new file mode 100644
index 0000000..0dd0c05
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestOptionalMultipleInstantiation.java
@@ -0,0 +1,214 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalMultipleInstantiation extends Common {
+
+ private ComponentFactory bar2Factory;
+ private ComponentInstance empty;
+
+ @Before
+ public void setUp() {
+ bar2Factory = (ComponentFactory) ipojoHelper.getFactory("composite.bar.4");
+ assertNotNull("Check bar2factory availability", bar2Factory);
+
+ Factory fact = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+ try {
+ empty = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the empty composite : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testCreation() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailability() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ assertNotNull("Check service availability", sc.getServiceReference(BarService.class.getName()));
+ int count = ipojoHelper.getServiceReferences(sc, BarService.class.getName(), null).length;
+ assertEquals("Check service provider number : " + count, count, 3);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testCreationLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailabilityLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+ assertNotNull("Check service availability", sc2.getServiceReference(BarService.class.getName()));
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2,
+ BarService.class.getName(), null).length, 3);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testFactoryManagement() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ ServiceContext sc = getServiceContext(under);
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc,
+ BarService.class.getName(), null).length, 2);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc,
+ BarService.class.getName(), null).length, 1);
+
+ fact3.stop();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc,
+ BarService.class.getName(), null).length, 0);
+
+ fact1.start();
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc,
+ BarService.class.getName(), null).length, 1);
+ assertTrue("Check instance validity - 5", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test
+ public void testFactoryManagementLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar2Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2,
+ BarService.class.getName(), null).length, 2);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2,
+ BarService.class.getName(), null).length, 1);
+
+ fact3.stop();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2,
+ BarService.class.getName(), null).length, 0);
+
+ fact1.start();
+ assertTrue("Check instance validity - 5", under.getState() == ComponentInstance.VALID);
+ assertEquals("Check service provider number", ipojoHelper.getServiceReferences(sc2,
+ BarService.class.getName(), null).length, 1);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestSimpleInstantiation.java b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestSimpleInstantiation.java
new file mode 100644
index 0000000..1310a64
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-instance-test/src/test/java/org/apache/felix/ipojo/runtime/core/instantiator/TestSimpleInstantiation.java
@@ -0,0 +1,274 @@
+/*
+ * 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.instantiator;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSimpleInstantiation extends Common {
+
+ private ComponentFactory bar1Factory;
+ private ComponentInstance empty;
+
+ @Before
+ public void setUp() {
+ bar1Factory = (ComponentFactory) ipojoHelper.getFactory("composite.bar.1");
+ Factory fact = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty-X");
+ try {
+ empty = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the empty composite : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testCreation() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailability() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc = getServiceContext(under);
+ assertNotNull("Check service availability", sc.getServiceReference(BarService.class.getName()));
+
+ under.dispose();
+ }
+
+ @Test
+ public void testCreationLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ under.dispose();
+ }
+
+ @Test
+ public void testServiceAvailabilityLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under-X");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity", under.getState() == ComponentInstance.VALID);
+ ServiceContext sc2 = getServiceContext(under);
+ assertNotNull("Check service availability", sc2.getServiceReference(BarService.class.getName()));
+
+ under.dispose();
+ }
+
+ @Test
+ public void testFactoryManagement() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test
+ public void testFactoryManagementLevel2() {
+ ServiceContext sc = getServiceContext(empty);
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props, sc);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ assertTrue("Check instance validity - 1", under.getState() == ComponentInstance.VALID);
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+ @Test
+ public void testArchitecture() {
+ Properties props = new Properties();
+ props.put("instance.name", "under");
+ ComponentInstance under = null;
+ try {
+ under = bar1Factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate under : " + e.getMessage());
+ }
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ Architecture arch = (Architecture) getContext().getService(ref);
+ CompositeInstanceDescription id = (CompositeInstanceDescription) arch.getInstanceDescription();
+
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ InstanceDescription[] contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ ComponentFactory fact1 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-1");
+ ComponentFactory fact2 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-2");
+ ComponentFactory fact3 = (ComponentFactory) ipojoHelper.getFactory("COMPO-FooBarProviderType-3");
+
+ fact1.stop();
+ assertTrue("Check instance validity - 2", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact2.stop();
+ assertTrue("Check instance validity - 3", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact3.stop();
+ assertTrue("Check instance invalidity", under.getState() == ComponentInstance.INVALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.INVALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 0);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ fact1.start();
+ assertTrue("Check instance validity - 4", under.getState() == ComponentInstance.VALID);
+ ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "under");
+ assertNotNull("Check architecture availability", ref);
+ arch = (Architecture) getContext().getService(ref);
+ //id = arch.getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ contained = id.getContainedInstances();
+ assertEquals("Check contained instances count", contained.length, 1);
+ assertEquals("Check instance name", id.getName(), "under");
+ assertEquals("Check component type name", id.getComponentDescription().getName(), "composite.bar.1");
+
+ under.dispose();
+ fact2.start();
+ fact3.start();
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/pom.xml b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/pom.xml
new file mode 100644
index 0000000..3ca125f
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.composite-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-composite-runtime-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
new file mode 100644
index 0000000..20e2773
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class Baz2CheckProvider implements CheckService {
+
+ BazService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(fs.foo()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+ private void voidUnbind() {
+ simpleU++;
+ }
+
+ protected void objectBind(Object o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+ protected void objectUnbind(Object o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
new file mode 100644
index 0000000..5711222
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+import java.util.Properties;
+
+public class BazProviderType1 implements BazService {
+
+ private int m_bar;
+ private String m_foo;
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ p.put("foo", m_foo);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..a0e9e43
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..700d9fe
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
new file mode 100644
index 0000000..84f9e36
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Tata;
+
+import java.util.Properties;
+
+
+public class TataProvider implements Tata {
+
+ int tata = 0;
+ int tataStr = 0;
+ int tataStrs = 0;
+ int tata_2 = 0;
+ int tata_3 = 0;
+ int tata1 = 0;
+ int tata1_1 = 0;
+ int tata5 = 0;
+ int tata5_1 = 0;
+ int tata5_2 = 0;
+ int tataBoolean = 0;
+ int tataBooleans = 0;
+ int tataByte = 0;
+ int tataBytes = 0;
+ private int add;
+ private int tataShorts;
+ private int tataShort;
+ private int tataLongs;
+ private int tataLong;
+ private int tataInts;
+ private int tataInt;
+ private int tataFloat;
+ private int tataFloats;
+ private int tataDoubles;
+ private int tataDouble;
+ private int tataChars;
+ private int tataChar;
+
+ public Properties getPropsTata() {
+ Properties props = new Properties();
+ props.put("tata", new Integer(tata));
+ props.put("tataStr", new Integer(tataStr));
+ props.put("tataStrs", new Integer(tataStrs));
+ props.put("tata_2", new Integer(tata_2));
+ props.put("tata_3", new Integer(tata_3));
+ props.put("tata1", new Integer(tata1));
+ props.put("tata1_1", new Integer(tata1_1));
+ props.put("tata5", new Integer(tata5));
+ props.put("tata5_1", new Integer(tata5_1));
+ props.put("tata5_2", new Integer(tata5_2));
+ props.put("add", new Integer(add));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataByte", new Integer(tataByte));
+ props.put("tataBytes", new Integer(tataBytes));
+ props.put("tataShort", new Integer(tataShort));
+ props.put("tataShorts", new Integer(tataShorts));
+ props.put("tataLongs", new Integer(tataLongs));
+ props.put("tataLong", new Integer(tataLong));
+ props.put("tataInt", new Integer(tataInt));
+ props.put("tataInts", new Integer(tataInts));
+ props.put("tataFloat", new Integer(tataFloat));
+ props.put("tataFloats", new Integer(tataFloats));
+ props.put("tataDouble", new Integer(tataDouble));
+ props.put("tataDoubles", new Integer(tataDoubles));
+ props.put("tataChar", new Integer(tataChar));
+ props.put("tataChars", new Integer(tataChars));
+ return props;
+ }
+
+ public void tata() {
+ tata++;
+ }
+
+ public String tataStr() {
+ tataStr++;
+ return "Tata";
+ }
+
+ public String[] tataStrs() {
+ tataStrs++;
+ return new String[] {"T", "A", "T", "A"};
+ }
+
+ public void tata(int i, int j) {
+ tata_2++;
+ }
+
+ public void tata(String s) {
+ tata_3++;
+ }
+
+ public String tata1(String a) {
+ tata1++;
+ return a;
+ }
+
+ public String tata1(char[] a) {
+ tata1_1++;
+ String s = new String(a);
+ return s;
+ }
+
+ public String tata5(String a, int i) {
+ tata5++;
+ return a+i;
+ }
+
+ public String tata5(String[] a, int i) {
+ tata5_1++;
+ return ""+a.length + i;
+ }
+
+ public String tata5(String a, int[] i) {
+ tata5_2++;
+ return a + i.length;
+ }
+
+ public boolean tataBoolean(boolean b) {
+ tataBoolean++;
+ return b;
+ }
+
+ public boolean[] tataBooleans(boolean[] b) {
+ tataBooleans++;
+ return b;
+ }
+
+ public byte tataByte(byte b) {
+ tataByte++;
+ return b;
+ }
+
+ public byte[] tataBytes(byte[] b) {
+ tataBytes++;
+ return b;
+ }
+
+ public char tataChar(char c) {
+ tataChar++;
+ return c;
+ }
+
+ public char[] tataChars(char[] c) {
+ tataChars++;
+ return c;
+ }
+
+ public double tataDouble(double d) {
+ tataDouble++;
+ return d;
+ }
+
+ public double[] tataDoubles(double[] d) {
+ tataDoubles++;
+ return d;
+ }
+
+ public float tataFloat(float f) {
+ tataFloat++;
+ return f;
+ }
+
+ public float[] tataFloats(float[] f) {
+ tataFloats++;
+ return f;
+ }
+
+ public int tataInt(int i) {
+ tataInt++;
+ return i;
+ }
+
+ public int[] tataInts(int[] its) {
+ tataInts++;
+ return its;
+ }
+
+ public long tataLong(long l) {
+ tataLong++;
+ return l;
+ }
+
+ public long[] tataLongs(long[] l) {
+ tataLongs++;
+ return l;
+ }
+
+ public short tataShort(short s) {
+ tataShort++;
+ return s;
+ }
+
+ public short[] tataShorts(short[] s) {
+ tataShorts++;
+ return s;
+ }
+
+ public long add(int i, int j, int k) {
+ add++;
+ return i + j + k;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
new file mode 100644
index 0000000..5c2c033
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProvider implements Toto {
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("toto", new Integer(toto));
+ props.put("toto_2", new Integer(toto_2));
+ props.put("toto_3", new Integer(toto_3));
+ props.put("toto_4", new Integer(toto_4));
+ props.put("toto1", new Integer(toto1));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
new file mode 100644
index 0000000..dccebaf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProviderGlue implements Toto {
+
+ Toto m_toto;
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ m_toto.toto();
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ m_toto.toto(i, j);
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ m_toto.toto1(j);
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("gtoto", new Integer(toto));
+ props.put("gtoto_2", new Integer(toto_2));
+ props.put("gtoto_3", new Integer(toto_3));
+ props.put("gtoto_4", new Integer(toto_4));
+ props.put("gtoto1", new Integer(toto1));
+ props.put("glue", "glue");
+ Properties p2 = m_toto.getProps();
+ props.putAll(p2);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..5e2b59a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
new file mode 100644
index 0000000..b9cec94
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BazService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
new file mode 100644
index 0000000..a65e2dd
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
@@ -0,0 +1,62 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tata {
+
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
new file mode 100644
index 0000000..82d307c
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
@@ -0,0 +1,78 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tota {
+
+ public static final String specification="specification { " +
+ "requires { " +
+ "$specification=\"org.apache.felix.ipojo.test.composite.service.Toto\" " +
+ "$optional=\"true\" " +
+ "$aggregate=\"true\" " +
+ "$type=\"service\" " +
+ "} }";
+
+ public Properties getProps() throws UnsupportedOperationException;;
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+ public void toto() throws UnsupportedOperationException;
+ public void toto(int i, int j) throws UnsupportedOperationException;
+ public String toto(String a) throws UnsupportedOperationException;
+
+ public void toto1(String j) throws UnsupportedOperationException;
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
new file mode 100644
index 0000000..037dad3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
@@ -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.runtime.core.services;
+
+import java.util.Properties;
+
+public interface Toto {
+
+ public Properties getProps();
+
+ public void toto();
+ public void toto(int i, int j);
+ public String toto(String a);
+ public String toto(String[] a);
+
+ public void toto1(String j);
+
+ public int count();
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/resources/metadata.xml b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..bd63765
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/main/resources/metadata.xml
@@ -0,0 +1,131 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite">
+ <!-- Used component type -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2" />
+ <property name="long" type="long" value="40" />
+ <property name="string" type="java.lang.String" value="foo" />
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" />
+ <property name="intAProp" type="int[]" value="{1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="COMPO-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="COMPO-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" />
+ <property name="boolean" field="boolProp" />
+ <property name="string" field="strProp" />
+ <property name="strAProp" field="strAProp" />
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.CheckServiceProvider"
+ name="COMPO-SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.test.composite.service.FooService, org.apache.felix.ipojo.test.composite.service.BarService }" />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-3" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.test.composite.service.FooService}">
+ <property name="baz" type="java.lang.String" value="foo" />
+ </provides>
+ <provides
+ specifications="{org.apache.felix.ipojo.test.composite.service.BarService}">
+ <property name="baz" type="java.lang.String" value="bar" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.BazProviderType1"
+ name="BazProviderType">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TataProvider"
+ name="tata">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProvider"
+ name="toto" architecture="true">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProviderGlue"
+ name="totoglue">
+ <requires field="m_toto" scope="composite" />
+ </component>
+
+ <!-- Composite -->
+ <comp:composite name="composite.empty" architecture="true">
+ </comp:composite>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Baz2CheckProvider" name="Baz2CheckProvider" architecture="true">
+ <requires field="fs" scope="composite"/>
+ <provides/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..0b3f1b9
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+@ExamReactorStrategy(PerMethod.class)
+public class Common extends BaseTest {
+
+ public static ServiceContext getServiceContext(ComponentInstance ci) {
+ if (ci instanceof CompositeManager) {
+ return ((CompositeManager) ci).getServiceContext();
+ } else {
+ throw new RuntimeException("Cannot get the service context from a non composite instance");
+ }
+ }
+
+ @Override
+ public boolean deployiPOJOComposite() {
+ return true;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/EmptyCompositeTest.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/EmptyCompositeTest.java
new file mode 100644
index 0000000..ade8665
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/EmptyCompositeTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.composite.CompositeInstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class EmptyCompositeTest extends Common {
+
+ @Test
+ public void testEmptyCompositeCreation() {
+ Factory factory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ ComponentTypeDescription cd = ci.getFactory().getComponentDescription();
+ assertEquals("Check component type name", cd.getName(), "composite.empty");
+// assertEquals("Check class name (" + cd.getClassName() + ")", cd.getClassName(), "composite");
+ assertEquals("Check offered service", cd.getprovidedServiceSpecification().length, 0);
+ assertEquals("Check configurable properties", cd.getProperties().length, 0);
+
+ CompositeInstanceDescription id = (CompositeInstanceDescription) ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state (" + id.getState() + ")", id.getState(), ComponentInstance.VALID);
+
+ assertEquals("Check contained instance", id.getContainedInstances().length, 0);
+
+ assertTrue("Check composite manager", ci instanceof CompositeManager);
+ CompositeManager cm = (CompositeManager) ci;
+ ServiceContext sc = cm.getServiceContext();
+ try {
+ assertEquals("Check number of factories imported", sc.getServiceReferences(Factory.class.getName(), null).length, getContext().getServiceReferences(Factory.class.getName(), null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e.getMessage());
+ }
+ ci.dispose();
+ }
+
+ @Test
+ public void testInstanceCreation1() {
+ Factory factory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ assertTrue("Check composite manager", ci instanceof CompositeManager);
+ CompositeManager cm = (CompositeManager) ci;
+ ServiceContext sc = cm.getServiceContext();
+ try {
+ assertEquals("Check number of factories imported", sc.getServiceReferences(Factory.class.getName(),
+ null).length, getContext().getServiceReferences(Factory.class.getName(), null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e.getMessage());
+ }
+
+ Properties props2 = new Properties();
+ props2.put("instance.name", "empty2");
+ ComponentInstance ci2 = null;
+ try {
+ ci2 = factory.createComponentInstance(props2, sc);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ CompositeInstanceDescription id = (CompositeInstanceDescription) ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 1);
+ CompositeInstanceDescription id2 = (CompositeInstanceDescription) id.getContainedInstances()[0];
+ assertEquals("Check composite instance name", id2.getName(), "empty2");
+ assertEquals("Check composite instance state", id2.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id2.getContainedInstances().length, 0);
+
+ ci2.dispose();
+ //id = ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 0);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testInstanceCreation2() {
+ Factory factory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ assertTrue("Check composite manager", ci instanceof CompositeManager);
+ CompositeManager cm = (CompositeManager) ci;
+ ServiceContext sc = cm.getServiceContext();
+ try {
+ assertEquals("Check number of factories imported", sc.getServiceReferences(Factory.class.getName(), null).length, getContext().getServiceReferences(Factory.class.getName(), null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e.getMessage());
+ }
+
+ Factory factory2 = ipojoHelper.getFactory(sc, "composite.empty");
+ assertNotNull("Check factory2 not null", factory2);
+ Properties props2 = new Properties();
+ props2.put("instance.name", "empty2");
+ ComponentInstance ci2 = null;
+ try {
+ ci2 = factory2.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ CompositeInstanceDescription id = (CompositeInstanceDescription) ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 1);
+ CompositeInstanceDescription id2 = (CompositeInstanceDescription) id.getContainedInstances()[0];
+ assertEquals("Check composite instance name", id2.getName(), "empty2");
+ assertEquals("Check composite instance state", id2.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id2.getContainedInstances().length, 0);
+
+ ci2.dispose();
+ //id = ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 0);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testInstanceCreation3() {
+ Factory factory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty");
+
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ assertTrue("Check composite manager", ci instanceof CompositeManager);
+ CompositeManager cm = (CompositeManager) ci;
+ ServiceContext sc = cm.getServiceContext();
+ try {
+ assertEquals("Check number of factories imported", sc.getServiceReferences(Factory.class.getName(), null).length, getContext().getServiceReferences(Factory.class.getName(), null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e.getMessage());
+ }
+
+ Factory factory2 = ipojoHelper.getFactory(sc, "composite.empty");
+ assertNotNull("Check factory2 not null", factory2);
+ Properties props2 = new Properties();
+ props2.put("instance.name", "empty2");
+ ComponentInstance ci2 = null;
+ try {
+ ci2 = factory2.createComponentInstance(props2, sc);
+ } catch (Exception e) {
+ fail("Unacceptable configuration : " + e.getMessage());
+ }
+
+ CompositeInstanceDescription id = (CompositeInstanceDescription) ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 1);
+ CompositeInstanceDescription id2 = (CompositeInstanceDescription) id.getContainedInstances()[0];
+ assertEquals("Check composite instance name", id2.getName(), "empty2");
+ assertEquals("Check composite instance state", id2.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id2.getContainedInstances().length, 0);
+
+ ci2.dispose();
+ //id = ci.getInstanceDescription();
+ assertEquals("Check composite instance name", id.getName(), "empty");
+ assertEquals("Check composite instance state", id.getState(), ComponentInstance.VALID);
+ assertEquals("Check contained instance", id.getContainedInstances().length, 0);
+
+ ci.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/FactoryManagementTest.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/FactoryManagementTest.java
new file mode 100644
index 0000000..e357689
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/FactoryManagementTest.java
@@ -0,0 +1,330 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class FactoryManagementTest extends Common {
+
+ private FakeFactory fake1 = new FakeFactory("fake");
+ private FakeFactory fake2 = new FakeFactory("fake2");
+
+ private Factory emptyFactory;
+ private ComponentInstance empty;
+
+ private class FakeFactory implements Factory {
+
+ private String m_name;
+
+ public FakeFactory(String name) {
+ m_name = name;
+ }
+
+ public ComponentInstance createComponentInstance(Dictionary arg0) throws UnacceptableConfiguration {
+ return null;
+ }
+
+ public ComponentInstance createComponentInstance(Dictionary arg0, ServiceContext arg1) throws UnacceptableConfiguration {
+ return null;
+ }
+
+ public Element getDescription() {
+ return null;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public boolean isAcceptable(Dictionary arg0) {
+ return false;
+ }
+
+ public void reconfigure(Dictionary arg0) throws UnacceptableConfiguration {
+ }
+
+ public void addFactoryStateListener(FactoryStateListener arg0) {
+ }
+
+ public List getMissingHandlers() {
+ return null;
+ }
+
+ public List getRequiredHandlers() {
+ return null;
+ }
+
+ public void removeFactoryStateListener(FactoryStateListener arg0) {
+ }
+
+ public ComponentTypeDescription getComponentDescription() {
+ return null;
+ }
+
+ public String getClassName() {
+ return "";
+ }
+
+ public int getState() {
+ return Factory.VALID;
+ }
+
+ public BundleContext getBundleContext() {
+ return getContext();
+ }
+
+ public String getVersion() {
+ return null;
+ }
+
+ public Element getComponentMetadata() {
+ return null;
+ }
+
+ public List<ComponentInstance> getInstances() {
+ return new ArrayList<ComponentInstance>();
+ }
+
+ public List<String> getInstancesNames() {
+ return new ArrayList<String>();
+ }
+
+ }
+
+ @Before
+ public void setUp() {
+ emptyFactory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty-1");
+ try {
+ empty = emptyFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create empty instance " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testOneLevelExposition() {
+ ServiceReference[] parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ ServiceContext sc = getServiceContext(empty);
+ ServiceReference[] internalFactoryReferences = ipojoHelper.getServiceReferences(sc, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories", parentsFactoryReferences.length, internalFactoryReferences.length);
+
+ for (int i = 0; i < parentsFactoryReferences.length; i++) {
+ Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
+ assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, internalFactoryReferences, sc));
+ }
+ }
+
+ @Test
+ public void testTwoLevelExposition() {
+ ServiceReference[] parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ ServiceContext sc1 = getServiceContext(empty);
+ ServiceReference[] Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+ ServiceReference[] Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ for (int i = 0; i < Level1FactoryReferences.length; i++) {
+ Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
+ assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, Level2FactoryReferences, sc2));
+ }
+
+ empty2.dispose();
+ }
+
+ @Test
+ public void testDynamism() {
+ ServiceReference[] parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ ServiceContext sc1 = getServiceContext(empty);
+ ServiceReference[] Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+ ServiceReference[] Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ for (int i = 0; i < Level1FactoryReferences.length; i++) {
+ Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
+ assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, Level2FactoryReferences, sc2));
+ }
+
+ // Publish fake1
+ ServiceRegistration reg1 = getContext().registerService(Factory.class.getName(), fake1, null);
+
+ parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ sc1 = getServiceContext(empty);
+ Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+ sc2 = getServiceContext(empty2);
+ Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ // Publish fake2
+ ServiceRegistration reg2 = getContext().registerService(Factory.class.getName(), fake2, null);
+
+ parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ sc1 = getServiceContext(empty);
+ Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+ sc2 = getServiceContext(empty2);
+ Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ reg1.unregister();
+
+ parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ sc1 = getServiceContext(empty);
+ Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+ sc2 = getServiceContext(empty2);
+ Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ reg2.unregister();
+
+ parentsFactoryReferences = osgiHelper.getServiceReferences(Factory.class.getName(), null);
+ sc1 = getServiceContext(empty);
+ Level1FactoryReferences = ipojoHelper.getServiceReferences(sc1, Factory.class.getName(), null);
+ sc2 = getServiceContext(empty2);
+ Level2FactoryReferences = ipojoHelper.getServiceReferences(sc2, Factory.class.getName(), null);
+
+ assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
+ assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
+
+ empty2.dispose();
+ }
+
+ @Test
+ public void testInvocation() {
+ ServiceContext sc1 = getServiceContext(empty);
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+
+ Factory fact1 = ipojoHelper.getFactory(sc2, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc2, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ assertNotNull("Check ref existency", ref);
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+ client.dispose();
+ provider.dispose();
+ empty2.dispose();
+ }
+
+
+ private boolean isExposed(Factory fact, ServiceReference[] refs, ServiceContext sc) {
+ for (int i = 0; i < refs.length; i++) {
+ Factory f = (Factory) sc.getService(refs[i]);
+ if (fact.getName().equals(f.getName())) {
+ sc.ungetService(refs[i]);
+ return true;
+ }
+ sc.ungetService(refs[i]);
+ }
+ return false;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRangeTest.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRangeTest.java
new file mode 100644
index 0000000..88363ee
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRangeTest.java
@@ -0,0 +1,510 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class ServiceRangeTest extends Common {
+
+ private Factory emptyFactory;
+ private ComponentInstance empty;
+
+
+ @Before
+ public void setUp() {
+ emptyFactory = ipojoHelper.getFactory("composite.empty");
+ Properties props = new Properties();
+ props.put("instance.name", "empty-1");
+ try {
+ empty = emptyFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create empty instance " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ empty.dispose();
+ empty = null;
+ }
+
+ @Test
+ public void testLevelOne1() {
+ ServiceContext sc2 = getServiceContext(empty);
+
+ Factory fact1 = ipojoHelper.getFactory(sc2, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc2, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the context", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ provider.dispose();
+ client.dispose();
+
+ assertNull("Check foo service invisible inside the composite", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible from the context", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ }
+
+ @Test
+ public void testLevelOne2() {
+ ServiceContext sc2 = getServiceContext(empty);
+
+ Factory fact1 = ipojoHelper.getFactory(sc2, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc2, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the context", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ }
+
+ @Test
+ public void testLevelOne3() {
+ ServiceContext sc2 = getServiceContext(empty);
+
+ Factory fact1 = ipojoHelper.getFactory("COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the context", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ }
+
+ @Test
+ public void testLevelTwo1() {
+ ServiceContext sc1 = getServiceContext(empty);
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+
+ Factory fact1 = ipojoHelper.getFactory(sc2, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc2, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ empty2.dispose();
+ }
+
+ @Test
+ public void testLevelTwo2() {
+ ServiceContext sc1 = getServiceContext(empty);
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+
+ Factory fact1 = ipojoHelper.getFactory(sc1, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc1, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ empty2.dispose();
+ }
+
+ @Test
+ public void testLevelTwo3() {
+ ServiceContext sc1 = getServiceContext(empty);
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+
+ Factory fact1 = ipojoHelper.getFactory("COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory("COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ empty2.dispose();
+ }
+
+ @Test
+ public void testLevelTwo4() {
+ ServiceContext sc1 = getServiceContext(empty);
+ Factory fact = ipojoHelper.getFactory(sc1, "composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty2");
+ ComponentInstance empty2 = null;
+ try {
+ empty2 = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ fail("Cannot instantiate empty2 instance : " + e.getMessage());
+ }
+
+ ServiceContext sc2 = getServiceContext(empty2);
+
+ Factory fact1 = ipojoHelper.getFactory(sc2, "COMPO-SimpleCheckServiceProvider");
+ Properties props = new Properties();
+ props.put("instance.name", "client");
+ ComponentInstance client = null;
+ try {
+ client = fact1.createComponentInstance(props, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the client : " + e.getMessage());
+ }
+
+ Factory fact2 = ipojoHelper.getFactory(sc2, "COMPO-FooProviderType-1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "provider");
+ ComponentInstance provider = null;
+ try {
+ provider = fact2.createComponentInstance(props2, sc2);
+ } catch (Exception e) {
+ fail("Cannot instantiate the provider : " + e.getMessage());
+ }
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+ CheckService check = (CheckService) sc2.getService(ref);
+
+ assertTrue("Check invocation", check.check());
+
+ sc2.ungetService(ref);
+
+ // Check visibility
+ assertNotNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNotNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ // Check invisibilty
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+
+ client.dispose();
+ provider.dispose();
+
+ assertNull("Check foo service visible inside the composite 2", sc2.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service visible inside the composite 2", sc2.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the composite 1", sc1.getServiceReference(FooService.class.getName()));
+ assertNull("Check check service invisible inside the composite 1", sc1.getServiceReference(CheckService.class.getName()));
+ assertNull("Check foo service invisible inside the global", getContext().getServiceReference(FooService.class.getName()));
+ try {
+ assertNull("Check check service invisible inside the context", getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=client)"));
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e);
+ }
+ empty2.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRegistryTest.java b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRegistryTest.java
new file mode 100644
index 0000000..6c41da3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-runtime-test/src/test/java/org/apache/felix/ipojo/runtime/core/ServiceRegistryTest.java
@@ -0,0 +1,282 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.context.ServiceRegistry;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.junit.Test;
+import org.osgi.framework.*;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class ServiceRegistryTest extends Common {
+
+ private class svcListener implements ServiceListener {
+ public int registration = 0;
+ public int unregistration = 0;
+ public int modification = 0;
+
+ public void serviceChanged(ServiceEvent ev) {
+ if (ev.getType() == ServiceEvent.REGISTERED) {
+ registration++;
+ }
+ if (ev.getType() == ServiceEvent.UNREGISTERING) {
+ unregistration++;
+ }
+ if (ev.getType() == ServiceEvent.MODIFIED) {
+ modification++;
+ }
+ }
+ }
+
+ private class barProvider implements BarService {
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+ }
+
+ private class FakeComponent implements ComponentInstance {
+
+ public ComponentTypeDescription getComponentDescription() {
+ return null;
+ }
+
+ public BundleContext getContext() {
+ return null;
+ }
+
+ public ComponentFactory getFactory() {
+ return null;
+ }
+
+ public InstanceDescription getInstanceDescription() {
+ return null;
+ }
+
+ public String getInstanceName() {
+ return null;
+ }
+
+ public int getState() {
+ return 0;
+ }
+
+ public boolean isStarted() {
+ return false;
+ }
+
+ public void reconfigure(Dictionary dictionary) {
+ }
+
+ public void start() {
+ }
+
+ public void stop() {
+ }
+
+ public void dispose() {
+ }
+
+ public void addInstanceStateListener(InstanceStateListener arg0) {
+ }
+
+ public void removeInstanceStateListener(InstanceStateListener arg0) {
+ }
+
+ }
+
+ @Test
+ public void testRegistrationAndListener() {
+ ComponentInstance im = new FakeComponent();
+ ComponentInstance im2 = new FakeComponent();
+ ServiceRegistry registry = new ServiceRegistry(getContext());
+ assertNotNull("Assert registry not null", registry);
+ svcListener all = new svcListener();
+ try {
+ assertNull("Check that there is no available service", registry.getServiceReferences(null, null));
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+ registry.addServiceListener(all);
+
+ ServiceRegistration reg1 = registry.registerService(im, BarService.class.getName(), new barProvider(), null);
+
+ try {
+ assertEquals("Check number of registred service", 1, registry.getServiceReferences(null, null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ ServiceRegistration reg2 = registry.registerService(im2, BarService.class.getName(), new barProvider(), null);
+
+ try {
+ assertEquals("Check number of registred service", 2, registry.getServiceReferences(null, null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ assertEquals("Check the number of registration", 2, all.registration);
+
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put("foo", "bar");
+ reg1.setProperties(props);
+ assertEquals("Check the number of modification", 1, all.modification);
+
+ reg1.unregister();
+ assertEquals("Check the number of unregistration", 1, all.unregistration);
+
+ reg2.setProperties(props);
+ assertEquals("Check the number of modification", 2, all.modification);
+
+ reg2.unregister();
+ assertEquals("Check the number of unregistration", 2, all.unregistration);
+
+ registry.removeServiceListener(all);
+ }
+
+ @Test
+ public void testRegistrationAndFilter() {
+ ComponentInstance im = new FakeComponent();
+ ComponentInstance im2 = new FakeComponent();
+ ServiceRegistry registry = new ServiceRegistry(getContext());
+ svcListener filtered = new svcListener();
+
+ try {
+ assertNull("Check that there is no available service", registry.getServiceReferences(null, null));
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ registry.addServiceListener(filtered, "(foo=bar)");
+
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put("foo", "bar");
+ ServiceRegistration reg1 = registry.registerService(im, BarService.class.getName(), new barProvider(), props);
+
+ try {
+ assertEquals("Check number of registred service", 1, registry.getServiceReferences(null, null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ ServiceRegistration reg2 = registry.registerService(im2, BarService.class.getName(), new barProvider(), null);
+
+ try {
+ assertEquals("Check number of registred service", 2, registry.getServiceReferences(null, null).length);
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ assertEquals("Check the number of registration", 1, filtered.registration);
+
+ reg2.setProperties(props);
+ assertEquals("Check the number of modification", 1, filtered.modification);
+ // Follow the OSGi semantics of filters
+
+ reg1.unregister();
+ reg2.unregister();
+ assertEquals("Check the number of unregistration", 2, filtered.unregistration);
+ registry.removeServiceListener(filtered);
+ }
+
+ @Test
+ public void testGetService() {
+ ComponentInstance im = new FakeComponent();
+ ComponentInstance im2 = new FakeComponent();
+ ServiceRegistry registry = new ServiceRegistry(getContext());
+
+ try {
+ assertNull("Check that there is no available service", registry.getServiceReferences(null, null));
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("foo", "bar");
+ ServiceRegistration reg1 = registry.registerService(im, BarService.class.getName(), new barProvider(), props);
+
+ ServiceReference ref = registry.getServiceReference(BarService.class.getName());
+ assertNotNull("Check ref not null", ref);
+ assertEquals("Test property", ref.getProperty("foo"), "bar");
+ BarService bar = (BarService) registry.getService(im2, ref);
+ assertTrue("Test invocation", bar.bar());
+
+ reg1.unregister();
+ ref = registry.getServiceReference(BarService.class.getName());
+ assertNull("Check ref null", ref);
+ }
+
+ @Test
+ public void testGetFilteredService() {
+ ComponentInstance im = new FakeComponent();
+ ComponentInstance im2 = new FakeComponent();
+ ServiceRegistry registry = new ServiceRegistry(getContext());
+
+ try {
+ assertNull("Check that there is no available service", registry.getServiceReferences(null, null));
+ } catch (InvalidSyntaxException e) {
+ fail("Cannot query the registry : " + e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("foo", "bar");
+ ServiceRegistration reg1 = registry.registerService(im, BarService.class.getName(), new barProvider(), props);
+ ServiceRegistration reg2 = registry.registerService(im2, BarService.class.getName(), new barProvider(), null);
+
+ ServiceReference[] ref = null;
+ try {
+ ref = registry.getServiceReferences(BarService.class.getName(), "(foo=bar)");
+ } catch (InvalidSyntaxException e) {
+ fail("Registry query fail : " + e.getMessage());
+ }
+ assertNotNull("Check ref not null", ref);
+ assertEquals("Check ref count", ref.length, 1);
+ assertEquals("Test property", ref[0].getProperty("foo"), "bar");
+ BarService bar = (BarService) registry.getService(im2, ref[0]);
+ assertTrue("Test invocation", bar.bar());
+
+ ref = null;
+ reg1.unregister();
+ try {
+ ref = registry.getServiceReferences(BarService.class.getName(), "(bar=foo)");
+ } catch (InvalidSyntaxException e) {
+ fail("Registry query fail : " + e.getMessage());
+ }
+ assertNull("Check ref null", ref);
+
+ reg2.unregister();
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/pom.xml b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/pom.xml
new file mode 100644
index 0000000..66dae86
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.composite-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-composite-service-providing-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
new file mode 100644
index 0000000..20e2773
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Baz2CheckProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class Baz2CheckProvider implements CheckService {
+
+ BazService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(fs.foo()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+ private void voidUnbind() {
+ simpleU++;
+ }
+
+ protected void objectBind(Object o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+ protected void objectUnbind(Object o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
new file mode 100644
index 0000000..5711222
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/BazProviderType1.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+
+import java.util.Properties;
+
+public class BazProviderType1 implements BazService {
+
+ private int m_bar;
+ private String m_foo;
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ p.put("foo", m_foo);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..a0e9e43
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..700d9fe
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java
new file mode 100644
index 0000000..f772059
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceConsumer.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.Service;
+
+import java.util.Properties;
+
+public class ServiceConsumer implements CheckService {
+
+ private Service service;
+ private Properties props = new Properties();
+
+ public ServiceConsumer() {
+ props.put("1", new Integer(service.count()));
+ props.put("2", new Integer(service.count()));
+ props.put("3", new Integer(service.count()));
+ }
+
+ public boolean check() {
+ return service.count() > 0;
+ }
+
+ public Properties getProps() {
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java
new file mode 100644
index 0000000..9c2f212
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ServiceProvider.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Service;
+
+
+public class ServiceProvider implements Service {
+
+ private int i = 0;
+
+ public int count() {
+ i++;
+ return i;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
new file mode 100644
index 0000000..84f9e36
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TataProvider.java
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Tata;
+
+import java.util.Properties;
+
+
+public class TataProvider implements Tata {
+
+ int tata = 0;
+ int tataStr = 0;
+ int tataStrs = 0;
+ int tata_2 = 0;
+ int tata_3 = 0;
+ int tata1 = 0;
+ int tata1_1 = 0;
+ int tata5 = 0;
+ int tata5_1 = 0;
+ int tata5_2 = 0;
+ int tataBoolean = 0;
+ int tataBooleans = 0;
+ int tataByte = 0;
+ int tataBytes = 0;
+ private int add;
+ private int tataShorts;
+ private int tataShort;
+ private int tataLongs;
+ private int tataLong;
+ private int tataInts;
+ private int tataInt;
+ private int tataFloat;
+ private int tataFloats;
+ private int tataDoubles;
+ private int tataDouble;
+ private int tataChars;
+ private int tataChar;
+
+ public Properties getPropsTata() {
+ Properties props = new Properties();
+ props.put("tata", new Integer(tata));
+ props.put("tataStr", new Integer(tataStr));
+ props.put("tataStrs", new Integer(tataStrs));
+ props.put("tata_2", new Integer(tata_2));
+ props.put("tata_3", new Integer(tata_3));
+ props.put("tata1", new Integer(tata1));
+ props.put("tata1_1", new Integer(tata1_1));
+ props.put("tata5", new Integer(tata5));
+ props.put("tata5_1", new Integer(tata5_1));
+ props.put("tata5_2", new Integer(tata5_2));
+ props.put("add", new Integer(add));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataBoolean", new Integer(tataBoolean));
+ props.put("tataByte", new Integer(tataByte));
+ props.put("tataBytes", new Integer(tataBytes));
+ props.put("tataShort", new Integer(tataShort));
+ props.put("tataShorts", new Integer(tataShorts));
+ props.put("tataLongs", new Integer(tataLongs));
+ props.put("tataLong", new Integer(tataLong));
+ props.put("tataInt", new Integer(tataInt));
+ props.put("tataInts", new Integer(tataInts));
+ props.put("tataFloat", new Integer(tataFloat));
+ props.put("tataFloats", new Integer(tataFloats));
+ props.put("tataDouble", new Integer(tataDouble));
+ props.put("tataDoubles", new Integer(tataDoubles));
+ props.put("tataChar", new Integer(tataChar));
+ props.put("tataChars", new Integer(tataChars));
+ return props;
+ }
+
+ public void tata() {
+ tata++;
+ }
+
+ public String tataStr() {
+ tataStr++;
+ return "Tata";
+ }
+
+ public String[] tataStrs() {
+ tataStrs++;
+ return new String[] {"T", "A", "T", "A"};
+ }
+
+ public void tata(int i, int j) {
+ tata_2++;
+ }
+
+ public void tata(String s) {
+ tata_3++;
+ }
+
+ public String tata1(String a) {
+ tata1++;
+ return a;
+ }
+
+ public String tata1(char[] a) {
+ tata1_1++;
+ String s = new String(a);
+ return s;
+ }
+
+ public String tata5(String a, int i) {
+ tata5++;
+ return a+i;
+ }
+
+ public String tata5(String[] a, int i) {
+ tata5_1++;
+ return ""+a.length + i;
+ }
+
+ public String tata5(String a, int[] i) {
+ tata5_2++;
+ return a + i.length;
+ }
+
+ public boolean tataBoolean(boolean b) {
+ tataBoolean++;
+ return b;
+ }
+
+ public boolean[] tataBooleans(boolean[] b) {
+ tataBooleans++;
+ return b;
+ }
+
+ public byte tataByte(byte b) {
+ tataByte++;
+ return b;
+ }
+
+ public byte[] tataBytes(byte[] b) {
+ tataBytes++;
+ return b;
+ }
+
+ public char tataChar(char c) {
+ tataChar++;
+ return c;
+ }
+
+ public char[] tataChars(char[] c) {
+ tataChars++;
+ return c;
+ }
+
+ public double tataDouble(double d) {
+ tataDouble++;
+ return d;
+ }
+
+ public double[] tataDoubles(double[] d) {
+ tataDoubles++;
+ return d;
+ }
+
+ public float tataFloat(float f) {
+ tataFloat++;
+ return f;
+ }
+
+ public float[] tataFloats(float[] f) {
+ tataFloats++;
+ return f;
+ }
+
+ public int tataInt(int i) {
+ tataInt++;
+ return i;
+ }
+
+ public int[] tataInts(int[] its) {
+ tataInts++;
+ return its;
+ }
+
+ public long tataLong(long l) {
+ tataLong++;
+ return l;
+ }
+
+ public long[] tataLongs(long[] l) {
+ tataLongs++;
+ return l;
+ }
+
+ public short tataShort(short s) {
+ tataShort++;
+ return s;
+ }
+
+ public short[] tataShorts(short[] s) {
+ tataShorts++;
+ return s;
+ }
+
+ public long add(int i, int j, int k) {
+ add++;
+ return i + j + k;
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
new file mode 100644
index 0000000..5c2c033
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProvider implements Toto {
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("toto", new Integer(toto));
+ props.put("toto_2", new Integer(toto_2));
+ props.put("toto_3", new Integer(toto_3));
+ props.put("toto_4", new Integer(toto_4));
+ props.put("toto1", new Integer(toto1));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
new file mode 100644
index 0000000..dccebaf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/TotoProviderGlue.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+
+import java.util.Properties;
+
+
+public class TotoProviderGlue implements Toto {
+
+ Toto m_toto;
+
+ private int i = 0;
+ public static int toto = 0;
+ public static int toto_2 = 0;
+ public static int toto_3 = 0;
+ public static int toto_4 = 0;
+ public static int toto1 = 0;
+
+ public int count() {
+ return i;
+ }
+
+ public void toto() {
+ toto++;
+ m_toto.toto();
+ }
+
+ public void toto(int i, int j) {
+ toto_2++;
+ m_toto.toto(i, j);
+ }
+
+ public String toto(String a) {
+ toto_3++;
+ return a;
+ }
+
+ public String toto(String[] a) {
+ toto_4++;
+ return "toto";
+ }
+
+ public void toto1(String j) {
+ i++;
+ toto1++;
+ m_toto.toto1(j);
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("i", new Integer(i));
+ props.put("gtoto", new Integer(toto));
+ props.put("gtoto_2", new Integer(toto_2));
+ props.put("gtoto_3", new Integer(toto_3));
+ props.put("gtoto_4", new Integer(toto_4));
+ props.put("gtoto1", new Integer(toto1));
+ props.put("glue", "glue");
+ Properties p2 = m_toto.getProps();
+ props.putAll(p2);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
new file mode 100644
index 0000000..5e2b59a
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/A123/CheckService2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services.A123;
+
+public interface CheckService2 {
+
+ public boolean check();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
new file mode 100644
index 0000000..b9cec94
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BazService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BazService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java
new file mode 100644
index 0000000..6ef60bf
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Service.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface Service {
+
+ public int count();
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
new file mode 100644
index 0000000..a65e2dd
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tata.java
@@ -0,0 +1,62 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tata {
+
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
new file mode 100644
index 0000000..8f10422
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Tota.java
@@ -0,0 +1,78 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface Tota {
+
+ public static final String specification="specification { " +
+ "requires { " +
+ "$specification=\"org.apache.felix.ipojo.runtime.core.services.Toto\" " +
+ "$optional=\"true\" " +
+ "$aggregate=\"true\" " +
+ "$type=\"service\" " +
+ "} }";
+
+ public Properties getProps() throws UnsupportedOperationException;;
+ public Properties getPropsTata();
+
+ public void tata();
+
+ public int tataInt(int i);
+ public long tataLong(long l);
+ public double tataDouble(double d);
+ public char tataChar(char c);
+ public boolean tataBoolean(boolean b);
+ public short tataShort(short s);
+ public float tataFloat(float f);
+ public byte tataByte(byte b);
+
+ public int[] tataInts(int[] its);
+ public long[] tataLongs(long[] l);
+ public double[] tataDoubles(double[] d);
+ public char[] tataChars(char[] c);
+ public boolean[] tataBooleans(boolean[] b);
+ public short[] tataShorts(short[] s);
+ public float[] tataFloats(float[] f);
+ public byte[] tataBytes(byte[] b);
+
+ public String tataStr();
+ public String[] tataStrs();
+
+ public void tata(int i, int j);
+ public void tata(String s);
+
+ public String tata1(String a);
+ public String tata1(char[] a);
+
+ public String tata5(String a, int i);
+ public String tata5(String[] a, int i);
+ public String tata5(String a, int[] i);
+
+ public long add(int i, int j, int k);
+
+ public void toto() throws UnsupportedOperationException;
+ public void toto(int i, int j) throws UnsupportedOperationException;
+ public String toto(String a) throws UnsupportedOperationException;
+
+ public void toto1(String j) throws UnsupportedOperationException;
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
new file mode 100644
index 0000000..037dad3
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Toto.java
@@ -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.runtime.core.services;
+
+import java.util.Properties;
+
+public interface Toto {
+
+ public Properties getProps();
+
+ public void toto();
+ public void toto(int i, int j);
+ public String toto(String a);
+ public String toto(String[] a);
+
+ public void toto1(String j);
+
+ public int count();
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata-providing.xml b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata-providing.xml
new file mode 100644
index 0000000..a4cff41
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata-providing.xml
@@ -0,0 +1,174 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite">
+ <comp:composite name="composite.test.3" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ aggregate="true" filter="(factory.name=BazProviderType)" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService" />
+ </comp:composite>
+
+ <comp:composite name="composite.test.2" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.CheckService"
+ filter="(factory.name=Baz2CheckProvider)" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.CheckService" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ scope="composite" />
+ </comp:composite>
+
+ <comp:composite name="composite.test.1" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ filter="(factory.name=composite.test.3)" />
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.CheckService"
+ filter="(factory.name=composite.test.2)" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.CheckService" />
+ </comp:composite>
+
+ <comp:composite name="composite.instantiator" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService"
+ filter="(factory.name=composite.test.3)" />
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.BazService" />
+ <comp:provides action="export"
+ specification="org.apache.felix.ipojo.runtime.core.services.FooService" />
+ </comp:composite>
+
+ <!-- Test composition provides -->
+
+ <comp:composite name="comp-0" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota" />
+ </comp:composite>
+
+ <comp:composite name="comp-1" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota">
+ <delegation method="tataInt" policy="One" />
+ <delegation method="toto1" policy="All" />
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-2" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata"
+ aggregate="true" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto"
+ aggregate="true" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota">
+ <delegation method="tataInt" policy="One" />
+ <delegation method="toto1" policy="All" />
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-3" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto"
+ optional="true" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota">
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-4" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto"
+ optional="true" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota">
+ <delegation method="tataInt" policy="One" />
+ <delegation method="toto1" policy="All" />
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-5" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata"
+ aggregate="true" />
+ <!-- <subservice action="import" specification="org.apache.felix.ipojo.test.comp:composite.service.Toto" aggregate ="true" optional="true"/> -->
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota">
+ <delegation method="tataInt" policy="One" />
+ <delegation method="toto1" policy="All" />
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-6" architecture="true">
+ <subservice action="instantiate"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata"
+ aggregate="true" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto"
+ aggregate="true" optional="true" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto">
+ <delegation method="toto1" policy="All" />
+ </comp:provides>
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tata">
+ <delegation method="tataInt" policy="One" />
+ </comp:provides>
+ </comp:composite>
+
+ <comp:composite name="comp-7" architecture="true">
+ <instance component="tata" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota" />
+ </comp:composite>
+
+ <comp:composite name="comp-8" architecture="true">
+ <instance component="tata" />
+ <instance component="totoglue" />
+ <subservice action="import"
+ specification="org.apache.felix.ipojo.runtime.core.services.Toto" />
+ <comp:provides action="implement"
+ specification="org.apache.felix.ipojo.runtime.core.services.Tota" />
+ </comp:composite>
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata.xml b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..d70c60b
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/main/resources/metadata.xml
@@ -0,0 +1,131 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd
+ org.apache.felix.composite http://felix.apache.org/ipojo/schemas/SNAPSHOT/composite.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:comp="org.apache.felix.ipojo.composite">
+ <!-- Used component type -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="COMPO-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2" />
+ <property name="long" type="long" value="40" />
+ <property name="string" type="java.lang.String" value="foo" />
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" />
+ <property name="intAProp" type="int[]" value="{1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="COMPO-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="COMPO-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" />
+ <property name="boolean" field="boolProp" />
+ <property name="string" field="strProp" />
+ <property name="strAProp" field="strAProp" />
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" />
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.CheckServiceProvider"
+ name="COMPO-SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService, org.apache.felix.ipojo.runtime.core.services.BarService }" />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="COMPO-FooBarProviderType-3" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService}">
+ <property name="baz" type="java.lang.String" value="foo" />
+ </provides>
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.BarService}">
+ <property name="baz" type="java.lang.String" value="bar" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.BazProviderType1"
+ name="BazProviderType">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TataProvider"
+ name="tata">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProvider"
+ name="toto" architecture="true">
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.TotoProviderGlue"
+ name="totoglue">
+ <requires field="m_toto" scope="composite" />
+ </component>
+
+ <!-- Composite -->
+ <comp:composite name="composite.empty" architecture="true">
+ </comp:composite>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.Baz2CheckProvider" name="Baz2CheckProvider" architecture="true">
+ <requires field="fs" scope="composite"/>
+ <provides/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..bb3b603
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Bootstrap the test from this project
+ */
+@ExamReactorStrategy(PerMethod.class)
+public class Common extends BaseTest {
+
+ public static ServiceContext getServiceContext(ComponentInstance ci) {
+ if (ci instanceof CompositeManager) {
+ return ((CompositeManager) ci).getServiceContext();
+ } else {
+ throw new RuntimeException("Cannot get the service context from a non composite instance");
+ }
+ }
+
+ @Override
+ public boolean deployiPOJOComposite() {
+ return true;
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.components"
+ );
+ }
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCompositeAPI.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCompositeAPI.java
new file mode 100644
index 0000000..2bdfea2
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCompositeAPI.java
@@ -0,0 +1,184 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.runtime.core.services.BazService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestCompositeAPI extends Common {
+
+ @Test
+ public void testAPI() {
+ Factory fact1 = ipojoHelper.getFactory("composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty-1");
+ ComponentInstance empty = null;
+ try {
+ empty = fact1.createComponentInstance(p);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ ServiceContext sc = getServiceContext(empty);
+
+ Factory fact2 = ipojoHelper.getFactory("composite.test.2");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "2"); // 2
+ Factory fact3 = ipojoHelper.getFactory("composite.test.3");
+ Properties props3 = new Properties();
+ props3.put("instance.name", "3");
+ ComponentInstance comp2 = null;
+ ComponentInstance comp3 = null;
+ try {
+ comp2 = fact2.createComponentInstance(props2, sc);
+ comp3 = fact3.createComponentInstance(props3, sc);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ assertTrue("Test comp3", comp3.getState() == ComponentInstance.VALID);
+ assertTrue("Test comp2", comp2.getState() == ComponentInstance.VALID);
+
+ ServiceReference ref = null;
+
+ ref = ipojoHelper.getServiceReferenceByName(sc, CheckService.class.getName(), "2"); // 2
+
+ assertNotNull("Check ref", ref);
+ CheckService cs = (CheckService) sc.getService(ref);
+ assertTrue("Check invoke", cs.check());
+
+ comp3.dispose();
+ comp2.dispose();
+ empty.dispose();
+ }
+
+ @Test
+ public void testInstantiator() {
+ String type = "composite.instantiator";
+ Factory fact = ipojoHelper.getFactory(type);
+ ComponentInstance ci = null;
+ Properties p = new Properties();
+ p.put("instance.name", "mon_coeur");
+ try {
+ ci = fact.createComponentInstance(p);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ assertTrue("Check ci", ci.getState() == ComponentInstance.VALID);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(BazService.class.getName(), "mon_coeur");
+ assertNotNull("Check ref", ref);
+ BazService bs = (BazService) getContext().getService(ref);
+ assertTrue("Check invocation", bs.foo());
+ getContext().ungetService(ref);
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "mon_coeur");
+ assertNotNull("Check ref 2 ", ref);
+ FooService fs = (FooService) getContext().getService(ref);
+ assertTrue("Check invocation", fs.foo());
+ getContext().ungetService(ref);
+ ci.dispose();
+ }
+
+ @Test
+ public void testAPI2() {
+ Factory fact1 = ipojoHelper.getFactory("composite.empty");
+ Properties p = new Properties();
+ p.put("instance.name", "empty-2");
+ ComponentInstance empty = null;
+ try {
+ empty = fact1.createComponentInstance(p);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ServiceContext sc = getServiceContext(empty);
+
+ Factory fact2 = ipojoHelper.getFactory(sc, "composite.test.2");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "4");
+ Factory fact3 = ipojoHelper.getFactory(sc, "composite.test.3");
+ Properties props3 = new Properties();
+ props3.put("instance.name", "5");
+ ComponentInstance comp2 = null;
+ ComponentInstance comp3 = null;
+ try {
+ comp2 = fact2.createComponentInstance(props2, sc);
+ comp3 = fact3.createComponentInstance(props3, sc);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ assertTrue("Test comp3", comp3.getState() == ComponentInstance.VALID);
+ assertTrue("Test comp2", comp2.getState() == ComponentInstance.VALID);
+
+ ServiceReference ref = null;
+
+ ref = ipojoHelper.getServiceReferenceByName(sc, CheckService.class.getName(), "4");
+
+ assertNotNull("Check ref", ref);
+ CheckService cs = (CheckService) sc.getService(ref);
+ assertTrue("Check invoke", cs.check());
+
+ comp3.dispose();
+ comp2.dispose();
+ empty.dispose();
+ }
+
+ @Test
+ public void testApplication() {
+ Factory factory = ipojoHelper.getFactory("composite.test.1");
+ ComponentInstance ci = null;
+ Properties props = new Properties();
+ props.put("instance.name", "Test");
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot instantiate Test " + e.getMessage());
+ }
+
+ assertTrue("Check ci state", ci.getState() == ComponentInstance.VALID);
+
+ ServiceReference[] refs = null;
+ try {
+ refs = getContext().getServiceReferences(CheckService.class.getName(), "(instance.name=Test)");
+ } catch (InvalidSyntaxException e) {
+ fail("Invalid filter : " + e.getMessage());
+ }
+ assertNotNull("Check refs not null", refs);
+ CheckService cs = (CheckService) getContext().getService(refs[0]);
+
+ assertTrue("Check invocation", cs.check());
+ ci.dispose();
+
+ }
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp0.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp0.java
new file mode 100644
index 0000000..c8149db
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp0.java
@@ -0,0 +1,343 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp0 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentFactory tataFactory2;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create an instance : " + e.getMessage());
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ fail("Cannot create an instance : " + e.getMessage());
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-0");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot create an instance : " + e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertNotNull("Assert toto service - 1", getContext().getServiceReference(Toto.class.getName()));
+ assertTrue("Assert under state - 2", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 3", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ Integer tataStr = (Integer) props.get("tataStr");
+ Integer tataStrs = (Integer) props.get("tataStrs");
+ Integer tata_2 = (Integer) props.get("tata_2");
+ Integer tata_3 = (Integer) props.get("tata_3");
+ Integer tata1 = (Integer) props.get("tata1");
+ Integer tata1_1 = (Integer) props.get("tata1_1");
+ Integer tata5 = (Integer) props.get("tata5");
+ Integer tata5_1 = (Integer) props.get("tata5_1");
+ Integer tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 3", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 3", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 3", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 3", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 3", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 3", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 3", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 3", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 3", tata5_2.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 4", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ assertEquals("Assert tataStr - 4", tataStr.intValue(), 2);
+ assertEquals("Assert tataStrs - 4", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 4", tata_2.intValue(), 2);
+ assertEquals("Assert tata_3 - 4", tata_3.intValue(), 2);
+ assertEquals("Assert tata1 - 4", tata1.intValue(), 2);
+ assertEquals("Assert tata1_1 - 4", tata1_1.intValue(), 2);
+ assertEquals("Assert tata5 - 4", tata5.intValue(), 2);
+ assertEquals("Assert tata5_1 - 4", tata5_1.intValue(), 2);
+ assertEquals("Assert tata5_2 - 4", tata5_2.intValue(), 2);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 6", toto.intValue(), 3);
+ assertEquals("Assert toto_2 - 6", toto_2.intValue(), 3);
+ assertEquals("Assert toto_3 - 6", toto_3.intValue(), 3);
+ assertEquals("Assert toto_4 - 6", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 6", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 6", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 6", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 6", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 6", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 6", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 6", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 6", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 6", tata5_2.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ totoProv.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeArrays(Tota tota) {
+
+ int[] a = new int[]{1, 2, 3};
+ assertEquals("Assert invoke tataint[]", tota.tataInts(a), a);
+
+ long[] b = new long[]{1, 2, 3};
+ assertEquals("Assert invoke tataLong[]", tota.tataLongs(b), b);
+
+ double[] c = new double[]{1, 2, 3};
+ assertEquals("Assert invoke tataDouble[]", tota.tataDoubles(c), c);
+
+ char[] d = new char[]{'a', 'b', 'c'};
+ assertEquals("Assert invoke tataChar[]", tota.tataChars(d), d);
+
+ boolean[] e = new boolean[]{true, false};
+ assertEquals("Assert invoke tataBoolean[]", tota.tataBooleans(e), e);
+
+ byte[] f = new byte[]{(byte) 1};
+ assertEquals("Assert invoke tataByte[]", tota.tataBytes(f), f);
+
+ short[] g = new short[]{(short) 1};
+ assertEquals("Assert invoke tataShort[]", tota.tataShorts(g), g);
+
+ float[] h = new float[]{5, 6, 7};
+ assertEquals("Assert invoke tataFloat[]", tota.tataFloats(h), h);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeTata(Tota tota) {
+ tota.tata(1, 2);
+ tota.tata("tototototo");
+ }
+
+ private void invokeTata1(Tota tota) {
+ assertEquals("Assert tata1", tota.tata1("foo"), "foo");
+ assertEquals("Assert tata1 - 2", tota.tata1(new char[]{'a', 'b', 'c'}), "abc");
+ }
+
+ private void invokeTata5(Tota tota) {
+ assertEquals("Assert tata5 -1", tota.tata5("foo", 1), "foo" + 1);
+ assertEquals("Assert tata5 - 2", tota.tata5(new String[]{"a", "b", "c"}, 1), "31");
+ assertEquals("Assert tata5 - 3", tota.tata5("foo", new int[]{1, 2, 3}), "foo3");
+ }
+
+ private void invokeAdd(Tota tota) {
+ assertEquals("Assert add", tota.add(1, 1, 1), 3);
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ invokeArrays(tota);
+ invokeStr(tota);
+ invokeTata(tota);
+ invokeTata1(tota);
+ invokeTata5(tota);
+ invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp1.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp1.java
new file mode 100644
index 0000000..62af8b7
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp1.java
@@ -0,0 +1,341 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp1 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+ private ComponentFactory tataFactory2;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-1");
+ Properties props2 = new Properties();
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Cannot create the instance : " + e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 (" + under.getState() + ")", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ Integer tataStr = (Integer) props.get("tataStr");
+ Integer tataStrs = (Integer) props.get("tataStrs");
+ Integer tata_2 = (Integer) props.get("tata_2");
+ Integer tata_3 = (Integer) props.get("tata_3");
+ Integer tata1 = (Integer) props.get("tata1");
+ Integer tata1_1 = (Integer) props.get("tata1_1");
+ Integer tata5 = (Integer) props.get("tata5");
+ Integer tata5_1 = (Integer) props.get("tata5_1");
+ Integer tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 3", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 3", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 3", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 3", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 3", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 3", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 3", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 3", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 3", tata5_2.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 4", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ assertEquals("Assert tataStr - 4", tataStr.intValue(), 2);
+ assertEquals("Assert tataStrs - 4", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 4", tata_2.intValue(), 2);
+ assertEquals("Assert tata_3 - 4", tata_3.intValue(), 2);
+ assertEquals("Assert tata1 - 4", tata1.intValue(), 2);
+ assertEquals("Assert tata1_1 - 4", tata1_1.intValue(), 2);
+ assertEquals("Assert tata5 - 4", tata5.intValue(), 2);
+ assertEquals("Assert tata5_1 - 4", tata5_1.intValue(), 2);
+ assertEquals("Assert tata5_2 - 4", tata5_2.intValue(), 2);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 6", toto.intValue(), 3);
+ assertEquals("Assert toto_2 - 6", toto_2.intValue(), 3);
+ assertEquals("Assert toto_3 - 6", toto_3.intValue(), 3);
+ assertEquals("Assert toto_4 - 6", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 6", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 6", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 6", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 6", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 6", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 6", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 6", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 6", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 6", tata5_2.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), under.getInstanceName()));
+
+ totoProv.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), under.getInstanceName()));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeArrays(Tota tota) {
+
+ int[] a = new int[]{1, 2, 3};
+ assertEquals("Assert invoke tataint[]", tota.tataInts(a), a);
+
+ long[] b = new long[]{1, 2, 3};
+ assertEquals("Assert invoke tataLong[]", tota.tataLongs(b), b);
+
+ double[] c = new double[]{1, 2, 3};
+ assertEquals("Assert invoke tataDouble[]", tota.tataDoubles(c), c);
+
+ char[] d = new char[]{'a', 'b', 'c'};
+ assertEquals("Assert invoke tataChar[]", tota.tataChars(d), d);
+
+ boolean[] e = new boolean[]{true, false};
+ assertEquals("Assert invoke tataBoolean[]", tota.tataBooleans(e), e);
+
+ byte[] f = new byte[]{(byte) 1};
+ assertEquals("Assert invoke tataByte[]", tota.tataBytes(f), f);
+
+ short[] g = new short[]{(short) 1};
+ assertEquals("Assert invoke tataShort[]", tota.tataShorts(g), g);
+
+ float[] h = new float[]{5, 6, 7};
+ assertEquals("Assert invoke tataFloat[]", tota.tataFloats(h), h);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeTata(Tota tota) {
+ tota.tata(1, 2);
+ tota.tata("tototototo");
+ }
+
+ private void invokeTata1(Tota tota) {
+ assertEquals("Assert tata1", tota.tata1("foo"), "foo");
+ assertEquals("Assert tata1 - 2", tota.tata1(new char[]{'a', 'b', 'c'}), "abc");
+ }
+
+ private void invokeTata5(Tota tota) {
+ assertEquals("Assert tata5 -1", tota.tata5("foo", 1), "foo" + 1);
+ assertEquals("Assert tata5 - 2", tota.tata5(new String[]{"a", "b", "c"}, 1), "31");
+ assertEquals("Assert tata5 - 3", tota.tata5("foo", new int[]{1, 2, 3}), "foo3");
+ }
+
+ private void invokeAdd(Tota tota) {
+ assertEquals("Assert add", tota.add(1, 1, 1), 3);
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ invokeArrays(tota);
+ invokeStr(tota);
+ invokeTata(tota);
+ invokeTata1(tota);
+ invokeTata5(tota);
+ invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp2.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp2.java
new file mode 100644
index 0000000..f7e2f64
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp2.java
@@ -0,0 +1,238 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp2 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+ private ComponentFactory tataFactory2;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-2");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 (" + under.getState() + ")", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+
+ invokeAll(tota);
+
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 3 (" + toto_1.intValue() + ")", toto_1.intValue(), 1);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 4 (" + toto.intValue() + ")", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4 (" + toto_2.intValue() + ")", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 4", toto_1.intValue(), 3);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 6 (" + toto.intValue() + ")", toto.intValue(), 3);
+ assertEquals("Assert toto_2 - 6 (" + toto_2.intValue() + ")", toto_2.intValue(), 3);
+ assertEquals("Assert toto_3 - 6", toto_3.intValue(), 3);
+ assertEquals("Assert toto_4 - 6", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 6", toto_1.intValue(), 4);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ totoProv.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ tota.toto1("foo2");
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ invokeToto(tota);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp3.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp3.java
new file mode 100644
index 0000000..904d61c
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp3.java
@@ -0,0 +1,271 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp3 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+ private ComponentFactory tataFactory2;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-3");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 (" + under.getState() + ")", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 3 (" + toto_1.intValue() + ")", toto_1.intValue(), 1);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 4 (" + toto.intValue() + ")", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4 (" + toto_2.intValue() + ")", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 4", toto_1.intValue(), 2);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Stop the factory
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ totoProv.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAllOpt(tota);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ tataFactory.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ tota.toto1("foo");
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+ private void invokeAllOpt(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeTotoOpt(tota);
+ }
+
+ private void invokeTotoOpt(Tota tota) {
+ try {
+ tota.toto();
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+
+ try {
+ tota.toto(1, 2);
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ tota.toto1("foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp4.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp4.java
new file mode 100644
index 0000000..9982ae4
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp4.java
@@ -0,0 +1,270 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp4 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+ private ComponentFactory tataFactory2;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-4");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory2.start();
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 (" + under.getState() + ")", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 3 (" + toto_1.intValue() + ")", toto_1.intValue(), 1);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 4 (" + toto.intValue() + ")", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4 (" + toto_2.intValue() + ")", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 4", toto_1.intValue(), 2);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Stop the factory
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ totoProv.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAllOpt(tota);
+ // Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ tataFactory.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ tota.toto1("foo");
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+ private void invokeAllOpt(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeTotoOpt(tota);
+ }
+
+ private void invokeTotoOpt(Tota tota) {
+ try {
+ tota.toto();
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+
+ try {
+ tota.toto(1, 2);
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ tota.toto1("foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp5.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp5.java
new file mode 100644
index 0000000..5714a41
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp5.java
@@ -0,0 +1,272 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class TestComp5 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+ private ComponentFactory tataFactory2;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name","toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name","toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-5");
+ Properties props2 = new Properties();
+ props2.put("instance.name","ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch(Exception e) {
+ e.printStackTrace();
+ fail("Cannot create an instance from comp-5 : " + e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory2.start();
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 ("+under.getState()+")", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 3 ("+toto.intValue()+")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 3 (" + toto_1.intValue() + ")", toto_1.intValue(), 1);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 4 ("+toto.intValue()+")", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4 ("+toto_2.intValue()+")", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 4", toto_1.intValue(), 3);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Stop the factory
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ totoProv.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAllOpt(tota);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "ff"));
+
+ tataFactory.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName( Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte)2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short)5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1,2);
+ tota.toto1("foo");
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+ private void invokeAllOpt(Tota tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ invokeTotoOpt(tota);
+ }
+
+ private void invokeTotoOpt(Tota tota) {
+ try {
+ tota.toto();
+ fail("UnsupportedOperationException expected");
+ } catch(UnsupportedOperationException e) { }
+
+ try {
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ fail("UnsupportedOperationException expected");
+ } catch(UnsupportedOperationException e) { }
+
+
+ try {
+ tota.toto(1,2);
+ fail("UnsupportedOperationException expected");
+ } catch(UnsupportedOperationException e) { }
+
+ try {
+ tota.toto1("foo");
+ fail("UnsupportedOperationException expected");
+ } catch(UnsupportedOperationException e) { }
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp6.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp6.java
new file mode 100644
index 0000000..a222261
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp6.java
@@ -0,0 +1,295 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tata;
+import org.apache.felix.ipojo.runtime.core.services.Toto;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp6 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+
+ tataFactory.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-6");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ @Ignore("known as borekn after service dependency interceptors")
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ ServiceReference refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ ServiceReference refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNull("Assert no toto service - 1", refToto);
+ assertNull("Assert no tata service - 1", refTata);
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2 (" + under.getState() + ")", under.getState() == ComponentInstance.INVALID);
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNull("Assert no toto service - 2", refToto);
+ assertNull("Assert no tata service - 2", refTata);
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNotNull("Assert toto service - 3", refToto);
+ assertNotNull("Assert tata service - 3", refTata);
+ Toto toto = (Toto) getContext().getService(refToto);
+ Tata tata = (Tata) getContext().getService(refTata);
+
+ invokeAll(tata);
+ invokeToto(toto);
+
+ // Check toto
+ Properties props = toto.getProps();
+ Integer toto_0 = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 3 (" + toto_0.intValue() + ")", toto_0.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 3 (" + toto_1.intValue() + ")", toto_1.intValue(), 1);
+ //Check tata
+ props = tata.getPropsTata();
+ Integer tata_0 = (Integer) props.get("tata");
+ assertEquals("Assert tata - 3", tata_0.intValue(), 1);
+
+ getContext().ungetService(refToto);
+ getContext().ungetService(refTata);
+ toto = null;
+ tata = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNotNull("Assert toto service - 4", refToto);
+ assertNotNull("Assert tata service - 4", refTata);
+
+ toto = (Toto) getContext().getService(refToto);
+ tata = (Tata) getContext().getService(refTata);
+ invokeAll(tata);
+ invokeToto(toto);
+
+ // Check toto
+ props = toto.getProps();
+ toto_0 = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ toto_1 = (Integer) props.get("toto1");
+ assertEquals("Assert toto - 4 (" + toto_0.intValue() + ")", toto_0.intValue(), 2);
+ assertEquals("Assert toto_2 - 4 (" + toto_2.intValue() + ")", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert toto1 - 4", toto_1.intValue(), 3);
+ //Check tata
+ props = tata.getPropsTata();
+ tata_0 = (Integer) props.get("tata");
+ assertEquals("Assert tata - 4", tata_0.intValue(), 2);
+ getContext().ungetService(refToto);
+ getContext().ungetService(refTata);
+ toto = null;
+ tata = null;
+
+ // Stop the factory
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNull("Assert no toto service - 5", refToto);
+ assertNull("Assert no tata service - 5", refTata);
+
+ totoProv2.stop();
+ totoProv.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNotNull("Assert toto service - 6", refToto);
+ assertNotNull("Assert tata service - 6", refTata);
+ toto = (Toto) getContext().getService(refToto);
+ tata = (Tata) getContext().getService(refTata);
+
+ invokeAll(tata);
+ invokeTotoOpt(toto);
+ // Check tata
+ props = tata.getPropsTata();
+ tata_0 = (Integer) props.get("tata");
+ assertEquals("Assert tata - 6", tata_0.intValue(), 1);
+ getContext().ungetService(refToto);
+ getContext().ungetService(refTata);
+ toto = null;
+ tata = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ tataFactory.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ refToto = ipojoHelper.getServiceReferenceByName(Toto.class.getName(), "ff");
+ refTata = ipojoHelper.getServiceReferenceByName(Tata.class.getName(), "ff");
+ assertNull("Assert no toto service - 7", refToto);
+ assertNull("Assert no tata service - 7", refTata);
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tata tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeStr(Tata tota) {
+ tota.tataStr();
+ }
+
+ private void invokeToto(Toto tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ tota.toto1("foo");
+ }
+
+ private void invokeAll(Tata tota) {
+ invoke(tota);
+ //invokeArrays(tota);
+ invokeStr(tota);
+ //invokeTata(tota);
+ //invokeTata1(tota);
+ //invokeTata5(tota);
+ //invokeAdd(tota);
+ }
+
+ private void invokeTotoOpt(Toto tota) {
+ try {
+ tota.toto();
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+
+ try {
+ tota.toto(1, 2);
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ tota.toto1("foo");
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp7.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp7.java
new file mode 100644
index 0000000..f6389f4
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp7.java
@@ -0,0 +1,339 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp7 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentFactory tataFactory2;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-7");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ tataFactory.stop();
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 1);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ Integer tataStr = (Integer) props.get("tataStr");
+ Integer tataStrs = (Integer) props.get("tataStrs");
+ Integer tata_2 = (Integer) props.get("tata_2");
+ Integer tata_3 = (Integer) props.get("tata_3");
+ Integer tata1 = (Integer) props.get("tata1");
+ Integer tata1_1 = (Integer) props.get("tata1_1");
+ Integer tata5 = (Integer) props.get("tata5");
+ Integer tata5_1 = (Integer) props.get("tata5_1");
+ Integer tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 3", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 3", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 3", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 3", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 3", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 3", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 3", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 3", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 3", tata5_2.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 4", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 2);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ assertEquals("Assert tataStr - 4", tataStr.intValue(), 2);
+ assertEquals("Assert tataStrs - 4", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 4", tata_2.intValue(), 2);
+ assertEquals("Assert tata_3 - 4", tata_3.intValue(), 2);
+ assertEquals("Assert tata1 - 4", tata1.intValue(), 2);
+ assertEquals("Assert tata1_1 - 4", tata1_1.intValue(), 2);
+ assertEquals("Assert tata5 - 4", tata5.intValue(), 2);
+ assertEquals("Assert tata5_1 - 4", tata5_1.intValue(), 2);
+ assertEquals("Assert tata5_2 - 4", tata5_2.intValue(), 2);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ assertEquals("Assert toto - 6", toto.intValue(), 3);
+ assertEquals("Assert toto_2 - 6", toto_2.intValue(), 3);
+ assertEquals("Assert toto_3 - 6", toto_3.intValue(), 3);
+ assertEquals("Assert toto_4 - 6", toto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 6", 1, tata.intValue());
+ assertEquals("Assert tataStr - 6", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 6", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 6", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 6", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 6", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 6", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 6", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 6", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 6", tata5_2.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ totoProv.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeArrays(Tota tota) {
+
+ int[] a = new int[]{1, 2, 3};
+ assertEquals("Assert invoke tataint[]", tota.tataInts(a), a);
+
+ long[] b = new long[]{1, 2, 3};
+ assertEquals("Assert invoke tataLong[]", tota.tataLongs(b), b);
+
+ double[] c = new double[]{1, 2, 3};
+ assertEquals("Assert invoke tataDouble[]", tota.tataDoubles(c), c);
+
+ char[] d = new char[]{'a', 'b', 'c'};
+ assertEquals("Assert invoke tataChar[]", tota.tataChars(d), d);
+
+ boolean[] e = new boolean[]{true, false};
+ assertEquals("Assert invoke tataBoolean[]", tota.tataBooleans(e), e);
+
+ byte[] f = new byte[]{(byte) 1};
+ assertEquals("Assert invoke tataByte[]", tota.tataBytes(f), f);
+
+ short[] g = new short[]{(short) 1};
+ assertEquals("Assert invoke tataShort[]", tota.tataShorts(g), g);
+
+ float[] h = new float[]{5, 6, 7};
+ assertEquals("Assert invoke tataFloat[]", tota.tataFloats(h), h);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeTata(Tota tota) {
+ tota.tata(1, 2);
+ tota.tata("tototototo");
+ }
+
+ private void invokeTata1(Tota tota) {
+ assertEquals("Assert tata1", tota.tata1("foo"), "foo");
+ assertEquals("Assert tata1 - 2", tota.tata1(new char[]{'a', 'b', 'c'}), "abc");
+ }
+
+ private void invokeTata5(Tota tota) {
+ assertEquals("Assert tata5 -1", tota.tata5("foo", 1), "foo" + 1);
+ assertEquals("Assert tata5 - 2", tota.tata5(new String[]{"a", "b", "c"}, 1), "31");
+ assertEquals("Assert tata5 - 3", tota.tata5("foo", new int[]{1, 2, 3}), "foo3");
+ }
+
+ private void invokeAdd(Tota tota) {
+ assertEquals("Assert add", tota.add(1, 1, 1), 3);
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ invokeArrays(tota);
+ invokeStr(tota);
+ invokeTata(tota);
+ invokeTata1(tota);
+ invokeTata5(tota);
+ invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp8.java b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp8.java
new file mode 100644
index 0000000..0f34872
--- /dev/null
+++ b/ipojo/runtime/composite-it/ipojo-composite-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/providing/TestComp8.java
@@ -0,0 +1,369 @@
+/*
+ * 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.providing;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.TotoProvider;
+import org.apache.felix.ipojo.runtime.core.components.TotoProviderGlue;
+import org.apache.felix.ipojo.runtime.core.services.Tota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestComp8 extends Common {
+
+ private ComponentFactory tataFactory;
+ private ComponentFactory totoFactory;
+ private ComponentFactory tataFactory2;
+ private ComponentInstance totoProv, totoProv2;
+ private ComponentInstance under;
+
+ @Before
+ public void setUp() {
+ tataFactory = (ComponentFactory) ipojoHelper.getFactory("tata");
+ totoFactory = (ComponentFactory) ipojoHelper.getFactory("toto");
+ tataFactory2 = (ComponentFactory) ipojoHelper.getFactory("comp-6");
+ tataFactory2.stop();
+
+ Properties props = new Properties();
+ props.put("instance.name", "toto provider");
+ try {
+ totoProv = totoFactory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Properties props3 = new Properties();
+ props3.put("instance.name", "toto provider 2");
+ try {
+ totoProv2 = totoFactory.createComponentInstance(props3);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ totoProv.stop();
+ totoProv2.stop();
+
+ Factory factory = ipojoHelper.getFactory("comp-8");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "ff");
+ try {
+ under = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ tataFactory.stop();
+
+ }
+
+ @After
+ public void tearDown() {
+ tataFactory.start();
+ totoProv.dispose();
+ totoProv = null;
+ totoProv2.dispose();
+ totoProv2 = null;
+ tataFactory2.start();
+
+ // Reset counters
+ TotoProvider.toto = 0;
+ TotoProvider.toto_2 = 0;
+ TotoProvider.toto_3 = 0;
+ TotoProvider.toto_4 = 0;
+ TotoProvider.toto1 = 0;
+ TotoProviderGlue.toto = 0;
+ TotoProviderGlue.toto_2 = 0;
+ TotoProviderGlue.toto_3 = 0;
+ TotoProviderGlue.toto_4 = 0;
+ TotoProviderGlue.toto1 = 0;
+ }
+
+ @Test
+ public void testSimple() {
+ // Neither factory nor instance
+ assertTrue("Assert under state - 1", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 1", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the importer
+ totoProv.start();
+ assertTrue("Assert under state - 2", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 2", getContext().getServiceReference(Tota.class.getName()));
+
+ // Start the factory
+ tataFactory.start();
+ assertTrue("Assert under state - 3", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 3", getContext().getServiceReference(Tota.class.getName()));
+ ServiceReference ref = getContext().getServiceReference(Tota.class.getName());
+ Tota tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ Properties props = tota.getProps();
+ Integer toto = (Integer) props.get("toto");
+ Integer toto_2 = (Integer) props.get("toto_2");
+ Integer toto_3 = (Integer) props.get("toto_3");
+ Integer toto_4 = (Integer) props.get("toto_4");
+ Integer gtoto = (Integer) props.get("gtoto");
+ Integer gtoto_2 = (Integer) props.get("gtoto_2");
+ Integer gtoto_3 = (Integer) props.get("gtoto_3");
+ Integer gtoto_4 = (Integer) props.get("gtoto_4");
+ assertEquals("Assert toto - 3 (" + toto.intValue() + ")", toto.intValue(), 1);
+ assertEquals("Assert toto_2 - 3", toto_2.intValue(), 1);
+ assertEquals("Assert toto_3 - 3", toto_3.intValue(), 0);
+ assertEquals("Assert toto_4 - 3", toto_4.intValue(), 0);
+ assertEquals("Assert gtoto - 3 (" + gtoto.intValue() + ")", gtoto.intValue(), 1);
+ assertEquals("Assert gtoto_2 - 3", gtoto_2.intValue(), 1);
+ assertEquals("Assert gtoto_3 - 3", gtoto_3.intValue(), 1);
+ assertEquals("Assert gtoto_4 - 3", gtoto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ Integer tata = (Integer) props.get("tata");
+ Integer tataStr = (Integer) props.get("tataStr");
+ Integer tataStrs = (Integer) props.get("tataStrs");
+ Integer tata_2 = (Integer) props.get("tata_2");
+ Integer tata_3 = (Integer) props.get("tata_3");
+ Integer tata1 = (Integer) props.get("tata1");
+ Integer tata1_1 = (Integer) props.get("tata1_1");
+ Integer tata5 = (Integer) props.get("tata5");
+ Integer tata5_1 = (Integer) props.get("tata5_1");
+ Integer tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 3", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 3", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 3", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 3", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 3", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 3", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 3", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 3", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 3", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 3", tata5_2.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Start a second import
+ totoProv2.start();
+ assertTrue("Assert under state - 4", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 4", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ gtoto = (Integer) props.get("gtoto");
+ gtoto_2 = (Integer) props.get("gtoto_2");
+ gtoto_3 = (Integer) props.get("gtoto_3");
+ gtoto_4 = (Integer) props.get("gtoto_4");
+ assertEquals("Assert toto - 4", toto.intValue(), 2);
+ assertEquals("Assert toto_2 - 4", toto_2.intValue(), 2);
+ assertEquals("Assert toto_3 - 4", toto_3.intValue(), 0);
+ assertEquals("Assert toto_4 - 4", toto_4.intValue(), 0);
+ assertEquals("Assert gtoto - 4 (" + gtoto.intValue() + ")", gtoto.intValue(), 2);
+ assertEquals("Assert gtoto_2 - 4", gtoto_2.intValue(), 2);
+ assertEquals("Assert gtoto_3 - 4", gtoto_3.intValue(), 2);
+ assertEquals("Assert gtoto_4 - 4", gtoto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 4", tata.intValue(), 2);
+ assertEquals("Assert tataStr - 4", tataStr.intValue(), 2);
+ assertEquals("Assert tataStrs - 4", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 4", tata_2.intValue(), 2);
+ assertEquals("Assert tata_3 - 4", tata_3.intValue(), 2);
+ assertEquals("Assert tata1 - 4", tata1.intValue(), 2);
+ assertEquals("Assert tata1_1 - 4", tata1_1.intValue(), 2);
+ assertEquals("Assert tata5 - 4", tata5.intValue(), 2);
+ assertEquals("Assert tata5_1 - 4", tata5_1.intValue(), 2);
+ assertEquals("Assert tata5_2 - 4", tata5_2.intValue(), 2);
+
+ getContext().ungetService(ref);
+ tota = null;
+
+ tataFactory.stop();
+ assertTrue("Assert under state - 5", under.getState() == ComponentInstance.INVALID);
+ assertNull("Assert no tota service - 5", getContext().getServiceReference(Tota.class.getName()));
+
+ totoProv2.stop();
+ tataFactory.start();
+ assertTrue("Assert under state - 6", under.getState() == ComponentInstance.VALID);
+ assertNotNull("Assert tota service - 6", getContext().getServiceReference(Tota.class.getName()));
+ ref = getContext().getServiceReference(Tota.class.getName());
+ tota = (Tota) getContext().getService(ref);
+ invokeAll(tota);
+ // Check toto
+ props = tota.getProps();
+ toto = (Integer) props.get("toto");
+ toto_2 = (Integer) props.get("toto_2");
+ toto_3 = (Integer) props.get("toto_3");
+ toto_4 = (Integer) props.get("toto_4");
+ gtoto = (Integer) props.get("gtoto");
+ gtoto_2 = (Integer) props.get("gtoto_2");
+ gtoto_3 = (Integer) props.get("gtoto_3");
+ gtoto_4 = (Integer) props.get("gtoto_4");
+ assertEquals("Assert toto - 6", toto.intValue(), 3);
+ assertEquals("Assert toto_2 - 6", toto_2.intValue(), 3);
+ assertEquals("Assert toto_3 - 6", toto_3.intValue(), 0);
+ assertEquals("Assert toto_4 - 6", toto_4.intValue(), 0);
+ assertEquals("Assert gtoto - 6 (" + gtoto.intValue() + ")", gtoto.intValue(), 3);
+ assertEquals("Assert gtoto_2 - 6", gtoto_2.intValue(), 3);
+ assertEquals("Assert gtoto_3 - 6", gtoto_3.intValue(), 3);
+ assertEquals("Assert gtoto_4 - 6", gtoto_4.intValue(), 0);
+ //Check tata
+ props = tota.getPropsTata();
+ tata = (Integer) props.get("tata");
+ tataStr = (Integer) props.get("tataStr");
+ tataStrs = (Integer) props.get("tataStrs");
+ tata_2 = (Integer) props.get("tata_2");
+ tata_3 = (Integer) props.get("tata_3");
+ tata1 = (Integer) props.get("tata1");
+ tata1_1 = (Integer) props.get("tata1_1");
+ tata5 = (Integer) props.get("tata5");
+ tata5_1 = (Integer) props.get("tata5_1");
+ tata5_2 = (Integer) props.get("tata5_2");
+ assertEquals("Assert tata - 6", tata.intValue(), 1);
+ assertEquals("Assert tataStr - 6", tataStr.intValue(), 1);
+ assertEquals("Assert tataStrs - 6", tataStrs.intValue(), 0);
+ assertEquals("Assert tata_2 - 6", tata_2.intValue(), 1);
+ assertEquals("Assert tata_3 - 6", tata_3.intValue(), 1);
+ assertEquals("Assert tata1 - 6", tata1.intValue(), 1);
+ assertEquals("Assert tata1_1 - 6", tata1_1.intValue(), 1);
+ assertEquals("Assert tata5 - 6", tata5.intValue(), 1);
+ assertEquals("Assert tata5_1 - 6", tata5_1.intValue(), 1);
+ assertEquals("Assert tata5_2 - 6", tata5_2.intValue(), 1);
+ getContext().ungetService(ref);
+ tota = null;
+
+ // Is arch exposed
+ assertNotNull("Test arch", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+
+ totoProv.stop();
+
+ assertTrue("Assert under state - 7", under.getState() == ComponentInstance.INVALID);
+ assertNotNull("Test arch-2", ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "ff"));
+ assertNull("Assert no tota service - 7", getContext().getServiceReference(Tota.class.getName()));
+
+ under.dispose();
+ under = null;
+ }
+
+ private void invoke(Tota tota) {
+ tota.tata();
+
+ assertEquals("Assert invoke tataint", tota.tataInt(2), 2);
+ assertEquals("Assert invoke tataLong", tota.tataLong(2), 2);
+ assertEquals("Assert invoke tataDouble", tota.tataDouble(2), 2, 0);
+ assertEquals("Assert invoke tataChar", tota.tataChar('a'), 'a');
+ assertTrue("Assert invoke tataBoolean", tota.tataBoolean(true));
+ assertEquals("Assert invoke tataByte", tota.tataByte((byte) 2), 2);
+ assertEquals("Assert invoke tataShort", tota.tataShort((short) 5), 5);
+ assertEquals("Assert invoke tataFloat", tota.tataFloat(5), 5, 0);
+
+ }
+
+ private void invokeArrays(Tota tota) {
+
+ int[] a = new int[]{1, 2, 3};
+ assertEquals("Assert invoke tataint[]", tota.tataInts(a), a);
+
+ long[] b = new long[]{1, 2, 3};
+ assertEquals("Assert invoke tataLong[]", tota.tataLongs(b), b);
+
+ double[] c = new double[]{1, 2, 3};
+ assertEquals("Assert invoke tataDouble[]", tota.tataDoubles(c), c);
+
+ char[] d = new char[]{'a', 'b', 'c'};
+ assertEquals("Assert invoke tataChar[]", tota.tataChars(d), d);
+
+ boolean[] e = new boolean[]{true, false};
+ assertEquals("Assert invoke tataBoolean[]", tota.tataBooleans(e), e);
+
+ byte[] f = new byte[]{(byte) 1};
+ assertEquals("Assert invoke tataByte[]", tota.tataBytes(f), f);
+
+ short[] g = new short[]{(short) 1};
+ assertEquals("Assert invoke tataShort[]", tota.tataShorts(g), g);
+
+ float[] h = new float[]{5, 6, 7};
+ assertEquals("Assert invoke tataFloat[]", tota.tataFloats(h), h);
+
+ }
+
+ private void invokeStr(Tota tota) {
+ tota.tataStr();
+ }
+
+ private void invokeTata(Tota tota) {
+ tota.tata(1, 2);
+ tota.tata("tototototo");
+ }
+
+ private void invokeTata1(Tota tota) {
+ assertEquals("Assert tata1", tota.tata1("foo"), "foo");
+ assertEquals("Assert tata1 - 2", tota.tata1(new char[]{'a', 'b', 'c'}), "abc");
+ }
+
+ private void invokeTata5(Tota tota) {
+ assertEquals("Assert tata5 -1", tota.tata5("foo", 1), "foo" + 1);
+ assertEquals("Assert tata5 - 2", tota.tata5(new String[]{"a", "b", "c"}, 1), "31");
+ assertEquals("Assert tata5 - 3", tota.tata5("foo", new int[]{1, 2, 3}), "foo3");
+ }
+
+ private void invokeAdd(Tota tota) {
+ assertEquals("Assert add", tota.add(1, 1, 1), 3);
+ }
+
+ private void invokeToto(Tota tota) {
+ tota.toto();
+ assertEquals("Assert toto", tota.toto("foo"), "foo");
+ tota.toto(1, 2);
+ }
+
+ private void invokeAll(Tota tota) {
+ invoke(tota);
+ invokeArrays(tota);
+ invokeStr(tota);
+ invokeTata(tota);
+ invokeTata1(tota);
+ invokeTata5(tota);
+ invokeAdd(tota);
+ invokeToto(tota);
+ }
+
+
+}
diff --git a/ipojo/runtime/composite-it/pom.xml b/ipojo/runtime/composite-it/pom.xml
new file mode 100644
index 0000000..ad6f640
--- /dev/null
+++ b/ipojo/runtime/composite-it/pom.xml
@@ -0,0 +1,354 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.runtime.composite-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Runtime Project ~ Composite Integration Tests</name>
+ <packaging>pom</packaging>
+
+ <properties>
+ <!-- Tests are enabled only when the 'test' profile is activated -->
+ <skipTestExecution>true</skipTestExecution>
+
+ <exam.version>3.0.1</exam.version>
+ <url.version>1.5.1</url.version>
+
+ <felix.version>4.2.0</felix.version>
+ <equinox.version>3.8.1.v20120830-144521</equinox.version>
+ <knoperflerfish.version>5.3.3</knoperflerfish.version>
+
+ <manipulator.version>1.12.1</manipulator.version>
+ </properties>
+
+ <modules>
+ <module>ipojo-composite-runtime-test</module>
+ <module>ipojo-composite-import-export-test</module>
+ <module>ipojo-composite-instance-test</module>
+ <module>ipojo-composite-service-providing-test</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.14.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <!-- TIME_FACTOR can be set from the command line with -DTIME_FACTOR=9-->
+ <TIME_FACTOR>${TIME_FACTOR}</TIME_FACTOR>
+ </systemPropertyVariables>
+ <skipTests>${skipTestExecution}</skipTests>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ <!-- Exclude iml files -->
+ <!-- Exclude target folders that may have been created during
+ the integration-tests -->
+ <exclude>src/it/**/target/**/*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.composite</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>${manipulator.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <version>1.8.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.1</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin</artifactId>
+ <!--
+ We use the released version as we don't really have to do any behavioral test on the handler in the core
+ test.
+ -->
+ <version>1.8.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>${felix.version}</version>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>${knoperflerfish.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>${equinox.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>${felix.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>test</id>
+ <properties>
+ <skipTestExecution>false</skipTestExecution>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/runtime/composite-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/composite-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/runtime/composite-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/runtime/composite/changelog.txt b/ipojo/runtime/composite/changelog.txt
new file mode 100644
index 0000000..639323f
--- /dev/null
+++ b/ipojo/runtime/composite/changelog.txt
@@ -0,0 +1,268 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.10.0 to 1.10.1
+-----------------------------
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3742] - Implementing class fails to load unless super interface's (interface extended by implemented interface) package is imported.
+ * [FELIX-3789] - Deadlock due to synchronization on INSTANCE_NAME
+ * [FELIX-3819] - The export directive of iPOJO is wrong
+
+Changes from the 1.8.2 to 1.8.4
+--------------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3500] - InstanceManager concurrency issue: "A methodID cannot be associated with a method from the POJO class"
+ * [FELIX-3501] - IPojo FactoryStateListener doesn't get notified while stopping factory
+ * [FELIX-3545] - Memory leak when unregistering a component used by an aggregate dependency with an unbind callback
+ * [FELIX-3548] - Concurrent access during startup
+ * [FELIX-3567] - iPOJO Configuration Handler should not reuse the dictionary object from the configuration admin
+ * [FELIX-3576] - iPOJO fails when using constructor injection and expecting BundleContext in ctor
+ * [FELIX-3599] - Problem with 'subservice action="instantiate"' in ipojo composite
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+ * [FELIX-3672] - Potential Concurrent Modification Exception when a bundle is stopped
+
+** Improvement
+ * [FELIX-3560] - Extensions to IPojo's Factory and ComponentInstance documentation for custom handlers
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+** Bug
+ * [FELIX-3130] - Nested composites throws StackOverflowError on instantiation
+ * [FELIX-3323] - Ipojo composite throw ClassCastException when configuration is updated thru ConfigAdmin
+ * [FELIX-3451] - "instance.name" attribute not recognized
+
+Changes from the 1.6.0 to 1.8.0
+-------------------------------
+** Improvement
+ * [FELIX-2746] - Composite should support instance configuration
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Improvement
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-994] - ClassCastException while Architecture on a composite with a provided service
+
+** Improvement
+ * Update parent pom
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-797] - Composite Architecture contains duplicate instances
+ * [FELIX-817] - iPOJO Service Exported throw an error when stopping
+
+Changes from 0.8.1 to 1.0.0
+---------------------------
+** Bug
+ * [FELIX-622] - iPOJO Composite Service Instance can use factories twice to create service instance
+ * [FELIX-628] - Architecture service should not publish the instance.name property
+ * [FELIX-637] - Composite service implementation does not support long argument
+
+** Improvement
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-688] - Better error reporting when an instance creation failed
+ * [FELIX-689] - Instance 'name' property should become 'instance.name'
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+
+Version 0.8.1
+-------------
+ * Initial release
diff --git a/ipojo/runtime/composite/obr.xml b/ipojo/runtime/composite/obr.xml
new file mode 100644
index 0000000..a39ed25
--- /dev/null
+++ b/ipojo/runtime/composite/obr.xml
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="instance"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ <p n="type" v="composite"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="subservice"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ <p n="type" v="composite"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="provides"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ <p n="type" v="composite"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="architecture"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ <p n="type" v="composite"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/runtime/composite/pom.xml b/ipojo/runtime/composite/pom.xml
new file mode 100644
index 0000000..5e96d84
--- /dev/null
+++ b/ipojo/runtime/composite/pom.xml
@@ -0,0 +1,189 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Composite</name>
+ <artifactId>org.apache.felix.ipojo.composite</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <properties>
+ <ipojo.package.version>1.12.1</ipojo.package.version>
+ </properties>
+
+ <description>
+ iPOJO Composition Model. This is an iPOJO extension to execute service composition.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-gettingstarted/ipojo-composition-tutorial.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO Composite</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>iPOJO Composition Layer
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-gettingstarted/ipojo-composition-tutorial.html
+ </Bundle-DocURL>
+ <Import-Package>
+ org.apache.felix.ipojo,
+ org.apache.felix.ipojo.architecture,
+ org.apache.felix.ipojo.context,
+ org.apache.felix.ipojo.metadata,
+ org.apache.felix.ipojo.parser,
+ org.apache.felix.ipojo.util,
+ org.osgi.framework;version=1.3,
+ !org.objectweb.asm.tree*,
+ !org.apache.felix.ipojo.xml.parser,
+ !org.apache.felix.ipojo.annotations,
+ *
+ </Import-Package>
+ <Private-Package>
+ org.apache.felix.ipojo.composite.architecture,
+ org.apache.felix.ipojo.composite.service*,
+ org.apache.felix.ipojo.composite.instance,
+ org.apache.felix.ipojo.composite.util,
+ <!-- ASM (Manipulator dependencies) -->
+ org.objectweb.asm.commons,
+ org.objectweb.asm.util,
+ org.objectweb.asm.signature,
+ org.objectweb.asm,
+ org.objectweb.asm.tree*,
+ org.apache.felix.ipojo.manipulation*,
+ org.apache.felix.ipojo.manipulator*
+ </Private-Package>
+ <Export-Package>
+ org.apache.felix.ipojo.composite; version="${ipojo.package.version}"
+ </Export-Package>
+ <IPOJO-Extension>
+ composite:org.apache.felix.ipojo.composite.CompositeFactory
+ </IPOJO-Extension>
+ <_donotcopy>(CVS|.svn|.+.bak|~.+|metadata.xml)</_donotcopy>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.10.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <metadata>src/main/resources/metadata.xml</metadata>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ <version>1.0-alpha-3</version>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+ <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+ <excludes>
+ <param>doc/**/*</param>
+ <param>maven-eclipse.xml</param>
+ <param>.checkstyle</param>
+ <param>.externalToolBuilders/*</param>
+ <param>LICENSE.asm</param>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.7</version>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java15</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/runtime/composite/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/composite/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..e23daaf
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,16 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/composite/src/main/appended-resources/META-INF/LICENSE b/ipojo/runtime/composite/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..1a5539d
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Composite:
+
+The Apache Felix iPOJO Composite includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/runtime/composite/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/composite/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..6f2e68f
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,4 @@
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeFactory.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeFactory.java
new file mode 100644
index 0000000..edf08c1
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeFactory.java
@@ -0,0 +1,180 @@
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.HandlerManager;
+import org.apache.felix.ipojo.IPojoContext;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.Tracker;
+import org.apache.felix.ipojo.util.TrackerCustomizer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * The component factory manages component instance objects. This management
+ * consist in creating and managing component instance build with the component
+ * factory. This class could export Factory and ManagedServiceFactory services.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeFactory extends ComponentFactory implements TrackerCustomizer {
+
+ /**
+ * Tracker used to track required handler factories.
+ */
+ protected Tracker m_tracker;
+
+ /**
+ * Create a composite factory.
+ * @param context : bundle context
+ * @param metadata : metadata of the component to create
+ * @throws ConfigurationException occurs when the element describing the factory is malformed.
+ */
+ public CompositeFactory(BundleContext context, Element metadata) throws ConfigurationException {
+ super(context, metadata);
+ }
+
+ /**
+ * Check if the metadata are well formed.
+ * @param metadata : metadata
+ * @throws ConfigurationException occurs when the element describing the factory is malformed.
+ * @see org.apache.felix.ipojo.ComponentFactory#check(org.apache.felix.ipojo.metadata.Element)
+ */
+ public void check(Element metadata) throws ConfigurationException {
+ String name = metadata.getAttribute("name");
+ if (name == null) {
+ throw new ConfigurationException("A composite needs a name : " + metadata);
+ }
+ }
+
+ public String getClassName() { return null; }
+
+ /**
+ * Compute required handlers.
+ * @return the list of required handler.
+ */
+ public List<RequiredHandler> getRequiredHandlerList() {
+ List<RequiredHandler> list = new ArrayList<RequiredHandler>();
+ Element[] elems = m_componentMetadata.getElements();
+ for (Element current : elems) {
+ RequiredHandler req = new RequiredHandler(current.getName(), current.getNameSpace());
+ if (!list.contains(req)) {
+ list.add(req);
+ }
+ }
+
+ // Add architecture if architecture != 'false'
+ String arch = m_componentMetadata.getAttribute("architecture");
+ if (arch == null || arch.equalsIgnoreCase("true")) {
+ RequiredHandler req = new RequiredHandler("architecture", null);
+ if (! list.contains(req)) { list.add(req); }
+ }
+
+ return list;
+ }
+
+ /**
+ * Stop all the instance managers.
+ */
+ public synchronized void stopping() {
+ if (m_tracker != null) {
+ m_tracker.close();
+ }
+ m_tracker = null;
+ }
+
+ /**
+ * Start all the instance managers.
+ */
+ public synchronized void starting() {
+ if (m_requiredHandlers.size() != 0) {
+ try {
+ String filter = "(&(" + Constants.OBJECTCLASS + "=" + HandlerFactory.class.getName() + ")"
+ + "(" + Handler.HANDLER_TYPE_PROPERTY + "=" + CompositeHandler.HANDLER_TYPE + ")"
+ + "(factory.state=1)"
+ + ")";
+ m_tracker = new Tracker(m_context, m_context.createFilter(filter), this);
+ m_tracker.open();
+ } catch (InvalidSyntaxException e) {
+ m_logger.log(Logger.ERROR, "A factory filter is not valid: " + e.getMessage());
+ stop();
+ }
+ }
+ }
+
+ /**
+ * Create an instance from the current factory.
+ * @param configuration : instance configuration
+ * @param context : bundle context to inject in the instance manager
+ * @param handlers : array of handler object to attached on the instance
+ * @return the created instance
+ * @throws ConfigurationException either the instance configuration or the instance starting has failed
+ * @see org.apache.felix.ipojo.ComponentFactory#createInstance(java.util.Dictionary, org.apache.felix.ipojo.IPojoContext, org.apache.felix.ipojo.HandlerManager[])
+ */
+ public ComponentInstance createInstance(Dictionary configuration, IPojoContext context, HandlerManager[] handlers) throws ConfigurationException {
+ CompositeManager inst = new CompositeManager(this, context, handlers);
+ inst.configure(m_componentMetadata, configuration);
+ inst.start();
+ return inst;
+ }
+
+ /**
+ * Reconfigure an existing instance.
+ * @param properties : the new configuration to push.
+ * @throws UnacceptableConfiguration : occurs if the new configuration is
+ * not consistent with the component type.
+ * @throws MissingHandlerException : occurs when an handler is unavailable when creating the instance.
+ * @see org.apache.felix.ipojo.Factory#reconfigure(java.util.Dictionary)
+ */
+ public synchronized void reconfigure(Dictionary properties) throws UnacceptableConfiguration, MissingHandlerException {
+ if (properties == null || (properties.get("instance.name") == null && properties.get("name") == null)) { // Support both instance.name and name
+ throw new UnacceptableConfiguration("The configuration does not contains the \"instance.name\" property");
+ }
+
+ String name = (String) properties.get("instance.name");
+ if (name == null) {
+ name = (String) properties.get("name");
+ }
+
+ ComponentInstance instance = m_componentInstances.get(name);
+ if (instance == null) { // The instance does not exists.
+ return;
+ }
+
+ instance.reconfigure(properties); // re-configure the component
+ }
+
+ public String getFactoryName() {
+ return m_componentMetadata.getAttribute("name"); // Mandatory attribute.
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeHandler.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeHandler.java
new file mode 100644
index 0000000..02ffe75
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeHandler.java
@@ -0,0 +1,83 @@
+/*
+ * 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.composite;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.util.Logger;
+
+
+/**
+ * Composite Handler Abstract Class. An composite handler need implements these
+ * method to be notified of lifecycle change...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class CompositeHandler extends Handler {
+
+ /**
+ * Composite Handler type.
+ */
+ public static final String HANDLER_TYPE = "composite";
+
+ /**
+ * Reference on the composite manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Composite Factory.
+ */
+ private CompositeFactory m_factory;
+
+ /**
+ * Sets the manager.
+ * This method must be called only once, and should not be overridden.
+ * @param instance : the composite manager.
+ */
+ protected void attach(ComponentInstance instance) {
+ m_manager = (CompositeManager) instance;
+ }
+
+ public final void setFactory(Factory factory) {
+ m_factory = (CompositeFactory) factory;
+ }
+
+ public final Logger getLogger() {
+ return m_factory.getLogger();
+ }
+
+ public final CompositeManager getCompositeManager() {
+ return m_manager;
+ }
+
+ /**
+ * Get a plugged handler of the same container.
+ * This method must be call only in the start method (or after).
+ * In the configure method, this method can not return a consistent
+ * result as all handlers are not plugged.
+ * @param name : name of the handler to find (class name).
+ * @return the composite handler object or null if the handler is not found.
+ */
+ public final Handler getHandler(String name) {
+ return m_manager.getCompositeHandler(name);
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeInstanceDescription.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeInstanceDescription.java
new file mode 100644
index 0000000..87793fc
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeInstanceDescription.java
@@ -0,0 +1,130 @@
+/*
+ * 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.composite;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+
+/**
+ * Composite Instance Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeInstanceDescription extends InstanceDescription {
+
+ /**
+ * Creates a Primitive Instance Description.
+ * @param type the component type description
+ * @param instance the instance description
+ */
+ public CompositeInstanceDescription(ComponentTypeDescription type, CompositeManager instance) {
+ super(type, instance);
+ }
+
+
+ /**
+ * Gets the list of contained instance in the described instance.
+ * This list contains only instances who exposed their architecture.
+ * @return the list of contained instances.
+ */
+ public InstanceDescription[] getContainedInstances() {
+ // Get instances description of internal instance
+ ServiceContext internal = ((CompositeManager) m_instance).getServiceContext();
+ try {
+ ServiceReference[] refs = internal.getServiceReferences(Architecture.class.getName(), null);
+ if (refs != null) {
+ InstanceDescription[] desc = new InstanceDescription[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ Architecture arch = (Architecture) internal.getService(refs[i]);
+ desc[i] = arch.getInstanceDescription();
+ internal.ungetService(refs[i]);
+ }
+ return desc;
+ }
+ } catch (InvalidSyntaxException e) {
+ // Cannot happen
+ }
+ return new InstanceDescription[0];
+ }
+
+ /**
+ * Gets the list of internally published services.
+ * @return the list of published services.
+ */
+ public Element getInternalServices() {
+ Element services = new Element("services", "");
+ ServiceContext internal = ((CompositeManager) m_instance)
+ .getServiceContext();
+ try {
+ ServiceReference[] refs = internal.getServiceReferences((String) null, "(!(objectclass=" + Factory.class
+ .getName() + "))");
+ for (int i = 0; refs != null && i < refs.length; i++) {
+ Element svc = new Element("service", "");
+ String[] keys = refs[i].getPropertyKeys();
+ for (int j = 0; j < keys.length; j++) {
+ Object v = refs[i].getProperty(keys[j]);
+ if (v instanceof String[]) {
+ List l = Arrays.asList((String[]) v);
+ svc.addAttribute(new Attribute(keys[j], l.toString()));
+ } else {
+ svc.addAttribute(new Attribute(keys[j], v.toString()));
+ }
+ }
+ services.addElement(svc);
+ }
+
+ } catch (InvalidSyntaxException e) {
+ // Cannot happen
+ }
+ return services;
+ }
+
+ /**
+ * Gets the instance description.
+ * Overridden to add created objects.
+ * @return the instance description
+ */
+ public Element getDescription() {
+ Element elem = super.getDescription();
+ elem.addElement(getInternalServices());
+
+ InstanceDescription[] descs = getContainedInstances();
+ if (descs.length > 0) {
+ Element inst = new Element("ContainedInstances", "");
+ for (int i = 0; i < descs.length; i++) {
+ inst.addElement(descs[i].getDescription());
+ }
+ elem.addElement(inst);
+ }
+
+ return elem;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeManager.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeManager.java
new file mode 100644
index 0000000..3ed565e
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeManager.java
@@ -0,0 +1,442 @@
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.HandlerManager;
+import org.apache.felix.ipojo.IPojoContext;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+
+/**
+ * iPOJO Composite manager. The composite manager class manages one instance of
+ * a component type which is a composition. It manages component lifecycle, and
+ * handlers...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeManager implements ComponentInstance, InstanceStateListener {
+
+ /**
+ * The context of the component.
+ */
+ private final BundleContext m_context;
+
+ /**
+ * Parent factory (ComponentFactory).
+ */
+ private final CompositeFactory m_factory;
+
+ /**
+ * Composite Handler list.
+ */
+ private HandlerManager[] m_handlers;
+
+ /**
+ * Instance State Listener List.
+ */
+ private List m_listeners = new ArrayList();
+
+ /**
+ * Internal service context of the composition.
+ */
+ private CompositeServiceContext m_internalContext;
+
+ /**
+ * The instance description.
+ */
+ private final CompositeInstanceDescription m_description;
+
+ /**
+ * Name of the component instance.
+ */
+ private String m_name;
+
+ /**
+ * Component state (STOPPED at the beginning).
+ */
+ private int m_state = STOPPED;
+
+ /**
+ * Logger.
+ */
+ private Logger m_logger;
+
+ /**
+ * Construct a new Component Manager.
+ * @param factory : the factory managing the instance manager
+ * @param context : the bundle context to give to the instance
+ * @param handlers : the handlers to plug
+ */
+ public CompositeManager(CompositeFactory factory, BundleContext context, HandlerManager[] handlers) {
+ m_factory = factory;
+ m_context = context;
+ // Initialize the service context.
+ m_internalContext = new CompositeServiceContext(m_context, this);
+ m_handlers = handlers;
+ m_description = new CompositeInstanceDescription(m_factory.getComponentDescription(), this);
+ m_logger = new Logger(m_context, this);
+
+ }
+
+ /**
+ * Plug the given handler to the current container.
+ * @param handler : the handler to plug.
+ */
+ public synchronized void addCompositeHandler(HandlerManager handler) {
+ if (m_handlers.length > 0) {
+ HandlerManager[] newInstances = new HandlerManager[m_handlers.length + 1];
+ System.arraycopy(m_handlers, 0, newInstances, 0, m_handlers.length);
+ newInstances[m_handlers.length] = handler;
+ m_handlers = newInstances;
+ } else {
+ m_handlers = new HandlerManager[] { handler };
+ }
+ }
+
+ /**
+ * Add an instance to the created instance list.
+ * @param listener : the instance state listener to add.
+ * @see org.apache.felix.ipojo.ComponentInstance#addInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
+ */
+ public void addInstanceStateListener(InstanceStateListener listener) {
+ synchronized (m_listeners) {
+ m_listeners.add(listener);
+ }
+ }
+
+ /**
+ * Configure the instance manager. Stop the existing handler, clear the
+ * handler list, change the metadata, recreate the handler
+ *
+ * @param metadata : the component type metadata
+ * @param configuration : the configuration of the instance
+ * @throws ConfigurationException : occurs when the component type are incorrect.
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ // Add the name
+ m_name = (String) configuration.get("instance.name");
+
+ // Create the standard handlers and add these handlers to the list
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].init(this, metadata, configuration);
+ }
+ }
+
+ /**
+ * Dispose the instance.
+ * @see org.apache.felix.ipojo.ComponentInstance#dispose()
+ */
+ public void dispose() {
+ if (m_state > STOPPED) { stop(); }
+
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ((InstanceStateListener) m_listeners.get(i)).stateChanged(this, DISPOSED);
+ }
+
+ m_factory.disposed(this);
+
+ // Cleaning
+ m_state = DISPOSED;
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].dispose();
+ }
+ m_handlers = new HandlerManager[0];
+ m_listeners.clear();
+ }
+
+ /**
+ * Return a specified handler.
+ * @param name : class name of the handler to find
+ * @return : the handler, or null if not found
+ */
+ public CompositeHandler getCompositeHandler(String name) {
+ for (int i = 0; i < m_handlers.length; i++) {
+ HandlerFactory fact = (HandlerFactory) m_handlers[i].getFactory();
+ if (fact.getHandlerName().equals(name) || name.equals(fact.getComponentDescription().getClassName())) {
+ return (CompositeHandler) m_handlers[i].getHandler();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the bundle context used by this instance.
+ * @return the parent context of the instance.
+ * @see org.apache.felix.ipojo.ComponentInstance#getContext()
+ */
+ public BundleContext getContext() {
+ return m_context;
+ }
+
+ /**
+ * Get the factory which create this instance.
+ * @return the factory of the component
+ * @see org.apache.felix.ipojo.ComponentInstance#getFactory()
+ */
+ public ComponentFactory getFactory() {
+ return m_factory;
+ }
+
+ /**
+ * Get the global bundle context.
+ * @return the global bundle context.
+ */
+ public BundleContext getGlobalContext() {
+ IPojoContext context = (IPojoContext) m_context;
+ return context.getGlobalContext();
+ }
+
+ /**
+ * Return the instance description of this instance.
+ * @return the instance description.
+ * @see org.apache.felix.ipojo.ComponentInstance#getInstanceDescription()
+ */
+ public InstanceDescription getInstanceDescription() {
+ return m_description;
+ }
+
+ /**
+ * Get the instance name.
+ * @return the instance name
+ * @see org.apache.felix.ipojo.ComponentInstance#getInstanceName()
+ */
+ public String getInstanceName() {
+ return m_name;
+ }
+
+ /**
+ * Get the parent service context.
+ * @return the parent service context.
+ */
+ public ServiceContext getParentServiceContext() {
+ IPojoContext context = (IPojoContext) m_context;
+ return context.getServiceContext();
+ }
+
+ /**
+ * REturn the list of handlers plugged on this instance.
+ * @return the list of the registered handlers.
+ */
+ public CompositeHandler[] getRegistredCompositeHandlers() {
+ CompositeHandler[] handler = new CompositeHandler[m_handlers.length];
+ for (int i = 0; i < m_handlers.length; i++) {
+ handler[i] = (CompositeHandler) m_handlers[i].getHandler();
+ }
+ return handler;
+ }
+
+ /**
+ * Get the internal service context of this instance.
+ * @return the internal service context.
+ */
+ public ServiceContext getServiceContext() {
+ return m_internalContext;
+ }
+
+ /**
+ * Get the actual state of the instance.
+ * @return the actual state of the instance
+ * @see org.apache.felix.ipojo.ComponentInstance#getState()
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ /**
+ * Check if the instance is started.
+ * @return true if the instance is started.
+ * @see org.apache.felix.ipojo.ComponentInstance#isStarted()
+ */
+ public boolean isStarted() {
+ return m_state > STOPPED;
+ }
+
+ /**
+ * Reconfigure the current instance.
+ * @param configuration : the new instance configuration.
+ * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary configuration) {
+ m_logger.log(Logger.INFO, "Reconfiguring composite with " + configuration);
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_logger.log(Logger.INFO, "Delegating reconfiguration to " + m_handlers[i].getClassName());
+ m_handlers[i].getHandler().reconfigure(configuration);
+ }
+ }
+
+ /**
+ * Remove an instance state listener.
+ * @param listener : the listener to remove
+ * @see org.apache.felix.ipojo.ComponentInstance#removeInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
+ */
+ public void removeInstanceStateListener(InstanceStateListener listener) {
+ synchronized (m_listeners) {
+ m_listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Set the state of the component.
+ * if the state changed call the stateChanged(int) method on the handlers.
+ * @param state : new state
+ */
+ public void setState(int state) {
+ if (m_state != state) {
+ if (state > m_state) {
+ // The state increases (Stopped = > IV, IV => V) => invoke handlers from the higher priority to the lower
+ m_state = state;
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].getHandler().stateChanged(state);
+ }
+ } else {
+ // The state decreases (V => IV, IV = > Stopped, Stopped => Disposed)
+ m_state = state;
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].getHandler().stateChanged(state);
+ }
+ }
+
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ((InstanceStateListener) m_listeners.get(i)).stateChanged(this, state);
+ }
+ }
+ }
+
+ /**
+ * Start the instance manager.
+ */
+ public synchronized void start() {
+ if (m_state > STOPPED) {
+ return;
+ } // Instance already started
+
+
+ // The new state of the component is UNRESOLVED
+ m_state = INVALID;
+
+ m_internalContext.start(); // Turn on the factory tracking
+
+ // Plug handler descriptions
+ Handler[] handlers = getRegistredCompositeHandlers();
+ for (int i = 0; i < handlers.length; i++) {
+ m_description.addHandler(handlers[i].getDescription());
+ }
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].start();
+ m_handlers[i].addInstanceStateListener(this);
+ }
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getState() != VALID) {
+ setState(INVALID);
+ return;
+ }
+ }
+ setState(VALID);
+
+ }
+
+ /**
+ * State Change listener callback.
+ * This method is notified at each time a plugged handler becomes invalid.
+ * @param instance : changing instance
+ * @param newState : new state
+ * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
+ */
+ public synchronized void stateChanged(ComponentInstance instance, int newState) {
+ if (m_state <= STOPPED) { return; }
+
+ // Update the component state if necessary
+ if (newState == INVALID && m_state == VALID) {
+ // Need to update the state to UNRESOLVED
+ setState(INVALID);
+ return;
+ }
+ if (newState == VALID && m_state == INVALID) {
+ // An handler becomes valid => check if all handlers are valid
+ boolean isValid = true;
+ for (int i = 0; i < m_handlers.length; i++) {
+ isValid = isValid && m_handlers[i].getState() == VALID;
+ }
+
+ if (isValid) { setState(VALID); }
+ }
+ if (newState == DISPOSED) {
+ kill();
+ }
+ }
+
+ /**
+ * Stop the instance manager.
+ */
+ public synchronized void stop() {
+ if (m_state <= STOPPED) {
+ return;
+ } // Instance already stopped
+
+ setState(INVALID);
+ // Stop all the handlers
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].removeInstanceStateListener(this);
+ m_handlers[i].stop();
+ }
+
+ m_internalContext.stop(); // Turn off the factory tracking
+ m_state = STOPPED;
+
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ((InstanceStateListener) m_listeners.get(i)).stateChanged(this, STOPPED);
+ }
+ }
+
+ /**
+ * Kill the current instance.
+ * Only the factory of this instance can call this method.
+ */
+ protected synchronized void kill() {
+ if (m_state > STOPPED) { stop(); }
+
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ((InstanceStateListener) m_listeners.get(i)).stateChanged(this, DISPOSED);
+ }
+
+ // Cleaning
+ m_state = DISPOSED;
+
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].dispose();
+ }
+ m_handlers = new HandlerManager[0];
+ m_listeners.clear();
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java
new file mode 100644
index 0000000..f514c27
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java
@@ -0,0 +1,506 @@
+/*
+ * 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.composite;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.*;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.IPojoContext;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.context.ServiceReferenceImpl;
+import org.apache.felix.ipojo.context.ServiceRegistry;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.util.Tracker;
+import org.apache.felix.ipojo.util.TrackerCustomizer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * CompositeServiceContext Class. This class provides an implementation of the
+ * service context for composite.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeServiceContext implements ServiceContext, TrackerCustomizer {
+
+ /**
+ * Structure storing the reference, the factory and the registration.
+ */
+ private class Record {
+ /**
+ * Reference of the represented factory from the external context.
+ */
+ private ServiceReference m_ref;
+ /**
+ * Registration of the factory in the internal context.
+ */
+ private ServiceRegistration m_reg;
+ /**
+ * Represented Factory.
+ */
+ private FactoryProxy m_fact;
+ }
+
+ /**
+ * List of imported factories.
+ */
+ private List<Record> m_factories = new ArrayList<Record>();
+ /**
+ * Internal service registry.
+ */
+ private ServiceRegistry m_registry;
+
+ /**
+ * Component Instance who creates this registry.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Global service context.
+ */
+ private BundleContext m_global;
+
+ /**
+ * Tracker tracking Factories to import.
+ */
+ private Tracker m_tracker;
+
+ /**
+ * Constructor. This constructor instantiate a service registry with the
+ * given bundle context.
+ *
+ * @param context : the bundle context
+ */
+ public CompositeServiceContext(BundleContext context) {
+ m_registry = new ServiceRegistry(context);
+ if (context instanceof IPojoContext) {
+ m_global = ((IPojoContext) context).getGlobalContext();
+ } else {
+ m_global = context; // the parent context is the global context
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context : the bundle context
+ * @param instance : the component instance owning this context
+ */
+ public CompositeServiceContext(BundleContext context, ComponentInstance instance) {
+ this(context);
+ m_instance = instance;
+ }
+
+ /**
+ * Add a service listener.
+ * @param arg0 : The service listener to add
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void addServiceListener(ServiceListener arg0) {
+ m_registry.addServiceListener(arg0);
+ }
+
+ /**
+ * Add a filtered service listener.
+ * @param arg0 : the service listener object to add
+ * @param arg1 : the LDAP filter for this listener
+ * @throws InvalidSyntaxException : occurs if the LDAP filter is malformed
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener,
+ * java.lang.String)
+ */
+ public void addServiceListener(ServiceListener arg0, String arg1) throws InvalidSyntaxException {
+ m_registry.addServiceListener(arg0, arg1);
+ }
+
+ /**
+ * Get all service references.
+ * @param arg0 : The required service interface.
+ * @param arg1 : LDAP filter
+ * @return the list of all service reference matching with the query
+ * @throws InvalidSyntaxException : occurs when the given filter is malformed
+ * @see org.apache.felix.ipojo.ServiceContext#getAllServiceReferences(java.lang.String,
+ * java.lang.String)
+ */
+ public ServiceReference[] getAllServiceReferences(String arg0, String arg1) throws InvalidSyntaxException {
+ return m_registry.getAllServiceReferences(arg0, arg1);
+ }
+
+ /**
+ * Get a service object for the given service reference.
+ * @param arg0 : the service reference
+ * @return the service object or null if the reference is no more valid or if the object is not accessible
+ * @see org.apache.felix.ipojo.ServiceContext#getService(org.osgi.framework.ServiceReference)
+ */
+ public Object getService(ServiceReference arg0) {
+ ServiceReference ref;
+ if (arg0 instanceof TransformedServiceReference) {
+ ref = ((TransformedServiceReference) arg0).getWrappedReference();
+ } else {
+ ref = arg0;
+ }
+
+ if (ref instanceof ServiceReferenceImpl) {
+ return m_registry.getService(m_instance, ref);
+ } else {
+ throw new RuntimeException("Cannot get a global service from the local registry");
+ }
+ }
+
+
+ /**
+ * Get a service reference for the required interface.
+ * @param arg0 : the required interface name
+ * @return the service reference or null if no available provider
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String)
+ */
+ public ServiceReference getServiceReference(String arg0) {
+ return m_registry.getServiceReference(arg0);
+ }
+
+ public <S> ServiceReference<S> getServiceReference(Class<S> clazz) {
+ //noinspection unchecked
+ return getServiceReference(clazz.getName());
+ }
+
+ @SuppressWarnings("unchecked")
+ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) throws InvalidSyntaxException {
+ ServiceReference<S>[] refs = getServiceReferences(clazz.getName(), filter);
+ return Arrays.asList(refs);
+ }
+
+ /**
+ * Get all accessible service reference for the given query.
+ * @param clazz : required interface
+ * @param filter : LDAP filter
+ * @return the list (array) of service reference matching with the query.
+ * @throws InvalidSyntaxException : occurs when the LDAP filter is malformed
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ return m_registry.getServiceReferences(clazz, filter);
+ }
+
+
+ /**
+ * Register a service inside the composite context.
+ * @param arg0 : list of interfaces to register.
+ * @param arg1 : service object
+ * @param arg2 : properties list
+ * @return the service registration
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String[] arg0, Object arg1, Dictionary arg2) {
+ return m_registry.registerService(m_instance, arg0, arg1, arg2);
+ }
+
+ /**
+ * Register a service inside the composite context.
+ * @param arg0 : interface to register.
+ * @param arg1 : service object
+ * @param arg2 : properties list
+ * @return the service registration
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String arg0, Object arg1, Dictionary arg2) {
+ return m_registry.registerService(m_instance, arg0, arg1, arg2);
+ }
+
+ /**
+ * Remove a service listener.
+ * @param arg0 : the service listener to remove
+ * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void removeServiceListener(ServiceListener arg0) {
+ m_registry.removeServiceListener(arg0);
+ }
+
+ /**
+ * Unget a service.
+ * @param arg0 the service reference to unget
+ * @return true
+ * @see org.apache.felix.ipojo.ServiceContext#ungetService(org.osgi.framework.ServiceReference)
+ */
+ public boolean ungetService(ServiceReference arg0) {
+ return m_registry.ungetService(m_instance, arg0);
+ }
+
+ /**
+ * Import a factory form the parent to the internal registry.
+ *
+ * @param ref : the reference of the factory to import.
+ */
+ private void importFactory(ServiceReference ref) {
+ Record rec = new Record();
+ m_factories.add(rec);
+ Dictionary<String, Object> dict = new Hashtable<String, Object>();
+ for (int j = 0; j < ref.getPropertyKeys().length; j++) {
+ dict.put(ref.getPropertyKeys()[j], ref.getProperty(ref.getPropertyKeys()[j]));
+ }
+ rec.m_fact = new FactoryProxy((Factory) m_tracker.getService(ref), this);
+ rec.m_reg = registerService(Factory.class.getName(), rec.m_fact, dict);
+ rec.m_ref = ref;
+ }
+
+ /**
+ * Remove a factory of the available factory list.
+ *
+ * @param ref : the reference on the factory to remove.
+ */
+ private void removeFactory(ServiceReference ref) {
+ for (int i = 0; i < m_factories.size(); i++) {
+ Record rec = m_factories.get(i);
+ if (rec.m_ref == ref) {
+ if (rec.m_reg != null) {
+ rec.m_reg.unregister();
+ rec.m_fact = null;
+ }
+ m_tracker.ungetService(rec.m_ref);
+ m_factories.remove(rec);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Start the registry management.
+ */
+ public void start() {
+ m_tracker = new Tracker(m_global, Factory.class.getName(), this);
+ m_tracker.open();
+ }
+
+ /**
+ * Stop the registry management.
+ */
+ public synchronized void stop() {
+ m_tracker.close();
+ m_registry.reset();
+ List<Record> records = new ArrayList<Record>(m_factories);
+ for (Record rec : records) {
+ removeFactory(rec.m_ref);
+ }
+ m_tracker = null;
+ }
+
+ /**
+ * Check if the factory list contain the given reference.
+ *
+ * @param ref : the reference to find.
+ * @return true if the list contains the given reference.
+ */
+ private boolean containsRef(ServiceReference ref) {
+ for (Record rec : m_factories) {
+ if (rec.m_ref == ref) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add a bundle listener.
+ * Delegate on the global bundle context.
+ * @param arg0 : bundle listener to add
+ * @see org.osgi.framework.BundleContext#addBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void addBundleListener(BundleListener arg0) {
+ m_global.addBundleListener(arg0);
+ }
+
+ /**
+ * Add a framework listener.
+ * Delegate on the global bundle context.
+ * @param arg0 : framework listener to add.
+ * @see org.osgi.framework.BundleContext#addFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void addFrameworkListener(FrameworkListener arg0) {
+ m_global.addFrameworkListener(arg0);
+ }
+
+ /**
+ * Create a LDAP filter.
+ * @param arg0 : String-form of the filter
+ * @return the created filter object
+ * @throws InvalidSyntaxException : if the given argument is not a valid against the LDAP grammar.
+ * @see org.osgi.framework.BundleContext#createFilter(java.lang.String)
+ */
+ public Filter createFilter(String arg0) throws InvalidSyntaxException {
+ return m_global.createFilter(arg0);
+ }
+
+ public Bundle getBundle(String location) {
+ return m_global.getBundle(location);
+ }
+
+ /**
+ * Get the current bundle.
+ * @return the current bundle
+ * @see org.osgi.framework.BundleContext#getBundle()
+ */
+ public Bundle getBundle() {
+ return m_global.getBundle();
+ }
+
+ /**
+ * Get the bundle object with the given id.
+ * @param bundleId : bundle id
+ * @return the bundle object
+ * @see org.osgi.framework.BundleContext#getBundle(long)
+ */
+ public Bundle getBundle(long bundleId) {
+ return m_global.getBundle(bundleId);
+ }
+
+ /**
+ * Get installed bundles.
+ * @return the list of installed bundles
+ * @see org.osgi.framework.BundleContext#getBundles()
+ */
+ public Bundle[] getBundles() {
+ return m_global.getBundles();
+ }
+
+
+ /**
+ * Get a data file.
+ * @param filename : File name.
+ * @return the File object
+ * @see org.osgi.framework.BundleContext#getDataFile(java.lang.String)
+ */
+ public File getDataFile(String filename) {
+ return m_global.getDataFile(filename);
+ }
+
+ /**
+ * Get a property value.
+ * @param key : key of the asked property
+ * @return the property value (object) or null if no property are associated with the given key
+ * @see org.osgi.framework.BundleContext#getProperty(java.lang.String)
+ */
+ public String getProperty(String key) {
+ return m_global.getProperty(key);
+ }
+
+ /**
+ * Install a bundle.
+ * @param location : URL of the bundle to install
+ * @return the installed bundle
+ * @throws BundleException : if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String)
+ */
+ public Bundle installBundle(String location) throws BundleException {
+ return m_global.installBundle(location);
+ }
+
+ /**
+ * Install a bundle.
+ * @param location : URL of the bundle to install
+ * @param input :
+ * @return the installed bundle
+ * @throws BundleException : if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String, java.io.InputStream)
+ */
+ public Bundle installBundle(String location, InputStream input) throws BundleException {
+ return m_global.installBundle(location, input);
+ }
+
+ /**
+ * Remove a bundle listener.
+ * @param listener : the listener to remove
+ * @see org.osgi.framework.BundleContext#removeBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void removeBundleListener(BundleListener listener) {
+ m_global.removeBundleListener(listener);
+ }
+
+ /**
+ * Remove a framework listener.
+ * @param listener : the listener to remove
+ * @see org.osgi.framework.BundleContext#removeFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void removeFrameworkListener(FrameworkListener listener) {
+ m_global.removeFrameworkListener(listener);
+ }
+
+ public <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> properties) {
+ return registerService(clazz.getName(), service, properties);
+ }
+
+ /**
+ * A new factory is detected.
+ * @param reference : service reference
+ * @return true if not already imported.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+ */
+ public boolean addingService(ServiceReference reference) {
+ return !containsRef(reference);
+ }
+
+ /**
+ * A matching reference has been added. The import factory can now be imported.
+ * @param reference : the added reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void addedService(ServiceReference reference) {
+ importFactory(reference);
+ }
+
+ /**
+ * An imported factory is modified.
+ * @param reference : modified reference
+ * @param service : factory object.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ for (Record rec : m_factories) {
+ if (rec.m_ref == reference) {
+ Dictionary<String, Object> dict = new Hashtable<String, Object>();
+ for (int j = 0; j < reference.getPropertyKeys().length; j++) {
+ dict.put(reference.getPropertyKeys()[j], reference.getProperty(reference.getPropertyKeys()[j]));
+ }
+ rec.m_reg.setProperties(dict);
+ return;
+ }
+ }
+ }
+
+ /**
+ * An imported factory disappears.
+ * @param reference : reference
+ * @param service : factory object.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ if (containsRef(reference)) {
+ removeFactory(reference);
+ }
+
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
new file mode 100644
index 0000000..f219810
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
@@ -0,0 +1,189 @@
+/*
+ * 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.composite;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.FactoryStateListener;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Bridge representing a Factory inside a composition.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FactoryProxy implements Factory {
+
+ /**
+ * Delegated factory.
+ */
+ private Factory m_delegate;
+
+ /**
+ * Destination context.
+ */
+ private ServiceContext m_context;
+
+ /**
+ * Constructor.
+ * @param fact : the targeted factory.
+ * @param svcContext : the service context to target.
+ */
+ public FactoryProxy(Factory fact, ServiceContext svcContext) {
+ m_delegate = fact;
+ m_context = svcContext;
+ }
+
+ /**
+ * Create an instance manager (i.e. component type instance).
+ * @param configuration : the configuration properties for this component.
+ * @return the created instance manager.
+ * @throws UnacceptableConfiguration : when a given configuration is not valid.
+ * @throws MissingHandlerException : occurs when the creation failed due to a missing handler (the factory should be invalid)
+ * @throws ConfigurationException : occurs when the creation failed due to a configuration issue
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
+ */
+ public ComponentInstance createComponentInstance(Dictionary configuration) throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+ return m_delegate.createComponentInstance(configuration, m_context);
+ }
+
+ /**
+ * Create an instance manager (i.e. component type instance). This has these service interaction in the scope given in argument.
+ * @param configuration : the configuration properties for this component.
+ * @param serviceContext : the service context of the component.
+ * @return the created instance manager.
+ * @throws UnacceptableConfiguration : when the given configuration is not valid.
+ * @throws MissingHandlerException : when at least one handler is missing.
+ * @throws ConfigurationException : when an issue occurs during the oconfiguration of the instance.
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary, org.apache.felix.ipojo.ServiceContext)
+ */
+ public ComponentInstance createComponentInstance(Dictionary configuration, ServiceContext serviceContext) throws UnacceptableConfiguration,
+ MissingHandlerException, ConfigurationException {
+ return m_delegate.createComponentInstance(configuration, serviceContext);
+ }
+
+ /**
+ * Get the component type information containing provided service, configuration properties ...
+ * @return the component type information.
+ * @see org.apache.felix.ipojo.Factory#getDescription()
+ */
+ public Element getDescription() {
+ return m_delegate.getDescription();
+ }
+
+ /**
+ * Return the factory name.
+ * @return the name of the factory.
+ * @see org.apache.felix.ipojo.Factory#getName()
+ */
+ public String getName() {
+ return m_delegate.getName();
+ }
+
+ /**
+ * Check if the given configuration is acceptable as a configuration of a component instance.
+ * @param conf : the configuration to test
+ * @return true if the configuration is acceptable
+ * @see org.apache.felix.ipojo.Factory#isAcceptable(java.util.Dictionary)
+ */
+ public boolean isAcceptable(Dictionary conf) {
+ return m_delegate.isAcceptable(conf);
+ }
+
+ /**
+ * Reconfigure an instance already created. This configuration need to have the name property to identify the instance.
+ * @param conf : the configuration to reconfigure the instance.
+ * @throws UnacceptableConfiguration : if the given configuration is not consistent for the targeted instance.
+ * @throws MissingHandlerException : when at least one handler is missing
+ * @see org.apache.felix.ipojo.Factory#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary conf) throws UnacceptableConfiguration, MissingHandlerException {
+ m_delegate.reconfigure(conf);
+ }
+
+ /**
+ * Add a factory listener.
+ * @param listener : the listener to add.
+ * @see org.apache.felix.ipojo.Factory#addFactoryStateListener(org.apache.felix.ipojo.FactoryStateListener)
+ */
+ public void addFactoryStateListener(FactoryStateListener listener) {
+ m_delegate.addFactoryStateListener(listener);
+
+ }
+
+ public List getMissingHandlers() {
+ return m_delegate.getMissingHandlers();
+ }
+
+ public List getRequiredHandlers() {
+ return m_delegate.getRequiredHandlers();
+ }
+
+ /**
+ * Remove a service listener.
+ * @param listener : the listener to remove
+ * @see org.apache.felix.ipojo.Factory#removeFactoryStateListener(org.apache.felix.ipojo.FactoryStateListener)
+ */
+ public void removeFactoryStateListener(FactoryStateListener listener) {
+ m_delegate.removeFactoryStateListener(listener);
+
+ }
+
+ public ComponentTypeDescription getComponentDescription() {
+ return m_delegate.getComponentDescription();
+ }
+
+ public String getClassName() {
+ return m_delegate.getClassName();
+ }
+
+ public int getState() {
+ return m_delegate.getState();
+ }
+
+ public BundleContext getBundleContext() {
+ return m_delegate.getBundleContext();
+ }
+
+ public String getVersion() {
+ return m_delegate.getVersion();
+ }
+
+ public Element getComponentMetadata() {
+ return m_delegate.getComponentMetadata();
+ }
+
+ public List<ComponentInstance> getInstances() {
+ return m_delegate.getInstances();
+ }
+
+ public List<String> getInstancesNames() {
+ return m_delegate.getInstancesNames();
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java
new file mode 100644
index 0000000..8286c86
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java
@@ -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.felix.ipojo.composite.architecture;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Composite Architecture Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ArchitectureHandler extends CompositeHandler implements Architecture, InstanceStateListener {
+
+ /**
+ * Name of the component.
+ */
+ private String m_name;
+
+ /**
+ * The Architecture service registration.
+ */
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ * Configure the handler.
+ *
+ * @param metadata : the metadata of the component
+ * @param configuration : the instance configuration
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) {
+ m_name = (String) configuration.get(Factory.INSTANCE_NAME_PROPERTY);
+ Dictionary<String, String> dict = new Hashtable<String, String>();
+ dict.put(ARCHITECTURE_INSTANCE, m_name);
+
+ debug("Registering architecture service for " + m_name);
+ m_serviceRegistration = getCompositeManager().getContext().registerService(Architecture.class.getName(), this, dict);
+
+ // We can't use the regular handler stateChanged method as this method is not called when the instance is
+ // disposed. This handler stays actives until the instance disposal.
+ getCompositeManager().addInstanceStateListener(this);
+ }
+
+ /**
+ * Stop method.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ // Nothing do do when stopping.
+ }
+
+ /**
+ * Start method.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Nothing to do.
+ }
+
+ /**
+ * The instance lifecycle listener callback.
+ * When we receive the DISPOSED state, the architecture is unregistered from the service registry.
+ * @param instance the changing instance the instance, meaningless in our case.
+ * @param newState the new instance state the new instance state.
+ */
+ public void stateChanged(ComponentInstance instance, int newState) {
+ if (newState == ComponentInstance.DISPOSED && m_serviceRegistration != null) {
+ debug("Withdrawing the architecture service of " + m_name + " due to instance disposal");
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+ }
+ }
+
+ /**
+ * Get the instance description.
+ * @return the instance description
+ * @see org.apache.felix.ipojo.architecture.Architecture#getInstanceDescription() ()
+ */
+ public InstanceDescription getInstanceDescription() {
+ return getCompositeManager().getInstanceDescription();
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandler.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandler.java
new file mode 100644
index 0000000..20b2a7b
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandler.java
@@ -0,0 +1,441 @@
+/*
+ * 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.composite.instance;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseException;
+
+/**
+ * Composite Instance Handler.
+ * This handler allows creating an instance inside a composite.
+ * This instance is determine by its type and a configuration.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstanceHandler extends CompositeHandler implements InstanceStateListener {
+
+ /**
+ * Internal context.
+ */
+ private ServiceContext m_scope;
+
+ /**
+ * Available factories.
+ */
+ private Factory[] m_factories;
+
+ /**
+ * Handler description.
+ */
+ private InstanceHandlerDescription m_description;
+
+
+ /**
+ * This structure aims to manage a configuration. It stores all necessary
+ * information to create an instance and to track the factory.
+ */
+ class ManagedConfiguration {
+ /**
+ * Configuration of the instance to create.
+ */
+ private Dictionary m_configuration;
+
+ /**
+ * Factory name.
+ */
+ private String m_factoryName;
+
+ /**
+ * Created instance.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Desired Factory (can be the classname).
+ */
+ private String m_desiredFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param conf : the configuration to create.
+ */
+ ManagedConfiguration(Dictionary conf) {
+ m_configuration = conf;
+ m_desiredFactory = (String) conf.get("component");
+ }
+
+ /**
+ * Return the managed configuration.
+ * @return the configuration.
+ */
+ protected Dictionary getConfiguration() {
+ return m_configuration;
+ }
+
+ /**
+ * Return the used factory name.
+ * @return the factory name
+ */
+ protected String getFactory() {
+ return m_factoryName;
+ }
+
+ protected String getNeededFactoryName() {
+ return m_desiredFactory;
+ }
+
+ /**
+ * Return the created instance.
+ * @return the instance (or null if no instance are created).
+ */
+ protected ComponentInstance getInstance() {
+ return m_instance;
+ }
+
+ /**
+ * Set the factory name.
+ *
+ * @param name : the factory name.
+ */
+ protected void setFactory(String name) {
+ m_factoryName = name;
+ }
+
+ /**
+ * Set the instance object.
+ *
+ * @param instance : the instance
+ */
+ protected void setInstance(ComponentInstance instance) {
+ m_instance = instance;
+ }
+ }
+
+ /**
+ * Configurations to create and maintains.
+ */
+ private ManagedConfiguration[] m_configurations = new ManagedConfiguration[0];
+
+ /**
+ * Create an instance using the given factory and the given configuration.
+ *
+ * @param fact : the factory name to used.
+ * @param config : the configuration.
+ */
+ private void createInstance(Factory fact, ManagedConfiguration config) {
+ Dictionary conf = config.getConfiguration();
+ try {
+ config.setInstance(fact.createComponentInstance(conf, m_scope));
+ config.setFactory(fact.getName());
+ config.getInstance().addInstanceStateListener(this);
+ } catch (UnacceptableConfiguration e) {
+ error("A factory is available for the configuration but the configuration is not acceptable", e);
+ } catch (MissingHandlerException e) {
+ error("The instance creation has failed, at least one handler is missing", e);
+ } catch (ConfigurationException e) {
+ error("The instance creation has failed, an error during the configuration has occured", e);
+ }
+ }
+
+ /**
+ * A new valid factory appears.
+ * @param factory : factory.
+ */
+ public void bindFactory(Factory factory) {
+ boolean implicated = false;
+ String factName = factory.getName();
+ String className = factory.getComponentDescription().getClassName();
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() == null
+ && (m_configurations[i].getNeededFactoryName().equals(factName)
+ || m_configurations[i].getNeededFactoryName().equals(className))) {
+ createInstance(factory, m_configurations[i]);
+ implicated = true;
+ }
+ }
+ if (implicated && ! getValidity()) {
+ checkValidity();
+ }
+ }
+
+ /**
+ * An existing factory disappears or becomes invalid.
+ * @param factory : factory
+ */
+ public void unbindFactory(Factory factory) {
+ boolean implicated = false;
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() != null
+ && m_configurations[i].getFactory().equals(factory.getName())) {
+ m_configurations[i].setInstance(null);
+ m_configurations[i].setFactory(null);
+ implicated = true;
+ }
+ }
+ if (implicated && getValidity()) {
+ checkValidity();
+ }
+ }
+
+ /**
+ * Stop all created instances.
+ */
+ public synchronized void stop() {
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() != null) {
+ m_configurations[i].getInstance().removeInstanceStateListener(this);
+ if (m_configurations[i].getInstance().getState() != ComponentInstance.DISPOSED) {
+ m_configurations[i].getInstance().dispose();
+ }
+ }
+ m_configurations[i].setInstance(null);
+ m_configurations[i].setFactory(null);
+ }
+ m_configurations = new ManagedConfiguration[0];
+ }
+
+ /**
+ * Configure method.
+ * @param metadata : component type metadata.
+ * @param configuration : instance configuration.
+ * @throws ConfigurationException : occurs an instance cannot be parsed correctly.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ m_scope = getCompositeManager().getServiceContext();
+
+ // Prepare the configuration to append.
+ Properties toAppend = new Properties();
+ Enumeration keys = configuration.keys();
+ while(keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (! (key.equals("instance.name")
+ || key.equals("component"))) { // Remove instance.name and component
+ toAppend.put(key, configuration.get(key));
+ }
+ }
+
+ Element[] instances = metadata.getElements("instance");
+ m_configurations = new ManagedConfiguration[instances.length];
+ for (int i = 0; i < instances.length; i++) {
+ Properties conf = null;
+ try {
+ conf = parseInstance(instances[i]);
+ } catch (ParseException e) {
+ error("An instance cannot be parsed correctly", e);
+ throw new ConfigurationException("An instance cannot be parsed correctly", e);
+ }
+
+ Properties instanceConfiguration = new Properties();
+ instanceConfiguration.putAll(conf);
+ instanceConfiguration.putAll(toAppend);
+ m_configurations[i] = new ManagedConfiguration(instanceConfiguration);
+ }
+
+ m_description = new InstanceHandlerDescription(this, m_configurations);
+ }
+
+ /**
+ * Parse an Element to get a dictionary.
+ * @param instance : the Element describing an instance.
+ * @return : the resulting dictionary
+ * @throws ParseException : occurs when a configuration cannot be parse correctly.
+ */
+ public static Properties parseInstance(Element instance) throws ParseException {
+ Properties dict = new Properties();
+ String name = instance.getAttribute("name");
+ if (name != null) {
+ dict.put("instance.name", name);
+ }
+
+ String comp = instance.getAttribute("component");
+ if (comp == null) {
+ throw new ParseException("An instance does not have the 'component' attribute");
+ } else {
+ dict.put("component", comp);
+ }
+
+ Element[] props = instance.getElements("property");
+ for (int i = 0; props != null && i < props.length; i++) {
+ parseProperty(props[i], dict);
+ }
+
+ return dict;
+ }
+
+ /**
+ * Parse a property.
+ * @param prop : the current element to parse
+ * @param dict : the dictionary to populate
+ * @throws ParseException : occurs if the property cannot be parsed correctly
+ */
+ public static void parseProperty(Element prop, Dictionary dict) throws ParseException {
+ // Check that the property has a name
+ String name = prop.getAttribute("name");
+ String value = prop.getAttribute("value");
+ if (name == null) { throw new ParseException("A property does not have the 'name' attribute"); }
+ // Final case : the property element has a 'value' attribute
+ if (value == null) {
+ // Recursive case
+ // Check if there is 'property' element
+ Element[] subProps = prop.getElements("property");
+ if (subProps == null) { throw new ParseException("A complex property must have at least one 'property' sub-element"); }
+ Dictionary dict2 = new Properties();
+ for (int i = 0; i < subProps.length; i++) {
+ parseProperty(subProps[i], dict2);
+ dict.put(prop.getAttribute("name"), dict2);
+ }
+ } else {
+ dict.put(name, value);
+ }
+ }
+
+ /**
+ * Start method.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ for (int j = 0; j < m_factories.length; j++) {
+ String factName = m_factories[j].getName();
+ String className = m_factories[j].getClassName();
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() == null && (m_configurations[i].getNeededFactoryName().equals(factName) || m_configurations[i].getNeededFactoryName().equals(className))) {
+ createInstance(m_factories[j], m_configurations[i]);
+ }
+ }
+ }
+ checkValidity();
+ }
+
+ /**
+ * Check handler validity.
+ * The method updates the validity of the handler.
+ */
+ private void checkValidity() {
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() == null || m_configurations[i].getInstance().getState() != ComponentInstance.VALID) {
+ setValidity(false);
+ return;
+ }
+ }
+ setValidity(true);
+ }
+
+ /**
+ * Instance state listener.
+ * This method listens when managed instance states change.
+ * @param instance : instance
+ * @param newState : the now state of the given instance
+ * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
+ */
+ public void stateChanged(ComponentInstance instance, int newState) {
+ switch (newState) {
+ case ComponentInstance.DISPOSED:
+ break; // Should not happen
+ case ComponentInstance.STOPPED:
+ break; // Should not happen
+ case ComponentInstance.VALID:
+ if (!getValidity()) {
+ checkValidity();
+ }
+ break;
+ case ComponentInstance.INVALID:
+ if (getValidity()) {
+ checkValidity();
+ }
+ break;
+ default:
+ break;
+
+ }
+ }
+
+ /**
+ * Method returning an instance object of the given component type.
+ * This method must be called only on 'primitive' type.
+ * @param type : type.
+ * @return an instance object or null if not found.
+ */
+ public Object getObjectFromInstance(String type) {
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() != null && type.equals(m_configurations[i].getFactory())) {
+ if (m_configurations[i].getInstance().getState() == ComponentInstance.VALID) {
+ return ((InstanceManager) m_configurations[i].getInstance()).getPojoObject();
+ } else {
+ error("An object cannot be get from the instance of the type " + type + ": invalid instance" +
+ m_configurations[i].getInstance().getInstanceDescription().getDescription());
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the handler description, i.e. the state of created instances.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Get the list of used component type.
+ * @return the list containing the used component type
+ */
+ public List getUsedType() {
+ List result = new ArrayList();
+ for (int i = 0; i < m_configurations.length; i++) {
+ result.add(m_configurations[i].getConfiguration().get("component"));
+ }
+ return result;
+ }
+
+ /**
+ * The composite is reconfigured, we check if we have a property to change.
+ * We reconfigure all contained instances.
+ * @param configuration the new instance configuration
+ */
+ public void reconfigure(Dictionary configuration) {
+ for (int i = 0; i < m_configurations.length; i++) {
+ if (m_configurations[i].getInstance() != null) {
+ info("Reconfiguring " + m_configurations[i].getInstance().getInstanceName());
+ m_configurations[i].getInstance().reconfigure(configuration);
+ }
+ }
+
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandlerDescription.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandlerDescription.java
new file mode 100644
index 0000000..a7fc53e
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/instance/InstanceHandlerDescription.java
@@ -0,0 +1,90 @@
+/*
+ * 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.composite.instance;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.composite.instance.InstanceHandler.ManagedConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Description of the Instance Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstanceHandlerDescription extends HandlerDescription {
+
+
+ /**
+ * List of managed instances.
+ */
+ private ManagedConfiguration[] m_configurations;
+
+ /**
+ * Constructor.
+ *
+ * @param handler : handler
+ * @param insts : list of component instances
+ */
+ public InstanceHandlerDescription(CompositeHandler handler, ManagedConfiguration[] insts) {
+ super(handler);
+ m_configurations = insts;
+ }
+
+ /**
+ * Build handler description.
+ * @return the handler description
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element instances = super.getHandlerInfo();
+ for (int i = 0; i < m_configurations.length; i++) {
+ ManagedConfiguration inst = m_configurations[i];
+ Element instance = new Element("Instance", "");
+ if (inst.getInstance() == null) {
+ instance.addAttribute(new Attribute("Factory", inst.getConfiguration().get("component").toString()));
+ instance.addAttribute(new Attribute("State", "Not Available"));
+ } else {
+ instance.addAttribute(new Attribute("Factory", inst.getFactory()));
+ instance.addAttribute(new Attribute("Name", inst.getInstance().getInstanceName()));
+ String state = null;
+ switch(inst.getInstance().getState()) {
+ case ComponentInstance.DISPOSED :
+ state = "disposed"; break;
+ case ComponentInstance.STOPPED :
+ state = "stopped"; break;
+ case ComponentInstance.VALID :
+ state = "valid"; break;
+ case ComponentInstance.INVALID :
+ state = "invalid"; break;
+ default :
+ break;
+ }
+ instance.addAttribute(new Attribute("State", state));
+ // The instance description is already contained inside parent instance description.
+ //instance.addElement(inst.getInstance().getInstanceDescription().getDescription());
+ }
+ instances.addElement(instance);
+ }
+ return instances;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceDependencyHandler.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceDependencyHandler.java
new file mode 100644
index 0000000..5712080
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceDependencyHandler.java
@@ -0,0 +1,393 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PolicyServiceContext;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.composite.instance.InstanceHandler;
+import org.apache.felix.ipojo.composite.util.SourceManager;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.util.DependencyMetadataHelper;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Service Instantiator Class. This handler allows to instantiate service
+ * instance inside the composition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceDependencyHandler extends CompositeHandler implements DependencyStateListener {
+
+ /**
+ * List of instances to manage.
+ */
+ private List/* <SvcInstance> */m_instances = new ArrayList();
+
+ /**
+ * List of importers.
+ */
+ private List/* <ServiceImporter> */ m_importers = new ArrayList();
+
+ /**
+ * Flag indicating if the handler has already finished the start method.
+ */
+ private boolean m_isStarted;
+
+ /**
+ * The handler description.
+ */
+ private ServiceInstantiatorDescription m_description;
+
+ /**
+ * Source Managers.
+ */
+ private List m_sources;
+
+
+ /**
+ * Create a Service instance object form the given Element.
+ * This method parse the given element and configure the service instance object.
+ * @param service : the Element describing the service instance
+ * @param conf : the configuration from the composite instance
+ * @throws ConfigurationException : the service instance cannot be created correctly
+ */
+ private void createServiceInstance(Element service, Dictionary conf) throws ConfigurationException {
+ // Prepare the configuration to append.
+ Properties toAppend = new Properties();
+ Enumeration keys = conf.keys();
+ while(keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (! (key.equals("instance.name")
+ || key.equals("component"))) { // Remove instance.name and component
+ toAppend.put(key, conf.get(key));
+ }
+ }
+
+ String spec = service.getAttribute("specification");
+ if (spec == null) {
+ throw new ConfigurationException("Malformed service : the specification attribute is mandatory");
+ }
+ String filter = "(&(!(factory.name=" + getCompositeManager().getFactory().getComponentDescription().getName() + "))(factory.state=1))"; // Cannot reinstantiate yourself
+ String givenFilter = service.getAttribute("filter");
+ if (givenFilter != null) {
+ filter = "(&" + filter + givenFilter + ")"; //NOPMD
+ }
+
+ Filter fil;
+ try {
+ fil = getCompositeManager().getGlobalContext().createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("Malformed filter " + filter, e);
+ }
+
+ Properties prop = new Properties();
+ Element[] props = service.getElements("property");
+ for (int k = 0; props != null && k < props.length; k++) {
+ try {
+ InstanceHandler.parseProperty(props[k], prop);
+ } catch (ParseException e) {
+ throw new ConfigurationException("An instance configuration is invalid", e);
+ }
+ }
+
+ Properties instanceConfiguration = new Properties();
+ instanceConfiguration.putAll(prop);
+ instanceConfiguration.putAll(toAppend);
+
+ String aggregate = service.getAttribute("aggregate");
+ boolean agg = aggregate != null && aggregate.equalsIgnoreCase("true");
+
+ String optional = service.getAttribute("optional");
+ boolean opt = optional != null && optional.equalsIgnoreCase("true");
+
+ int policy = DependencyMetadataHelper.getPolicy(service);
+
+ Comparator cmp = DependencyMetadataHelper.getComparator(service, getCompositeManager().getGlobalContext());
+
+ SvcInstance inst = new SvcInstance(this, spec, instanceConfiguration, agg, opt, fil, cmp, policy);
+ m_instances.add(inst);
+
+ String sources = service.getAttribute("context-source");
+ if (sources != null) {
+ SourceManager source = new SourceManager(sources, filter, inst, getCompositeManager());
+ if (m_sources == null) {
+ m_sources = new ArrayList(1);
+ }
+ m_sources.add(source);
+ }
+ }
+
+ /**
+ * Create a Service importer object from the given Element.
+ * This method parse the given element and configure the service importer object.
+ * @param imp : Element describing the import
+ * @param confFilter : instance filter customization
+ * @throws ConfigurationException : the service importer cannot be created correctly
+ */
+ private void createServiceImport(Element imp, Dictionary confFilter) throws ConfigurationException {
+ boolean optional = false;
+ boolean aggregate = false;
+ String specification = imp.getAttribute("specification");
+
+ if (specification == null) {
+ // Malformed import
+ error("Malformed import: the specification attribute is mandatory");
+ throw new ConfigurationException("Malformed import : the specification attribute is mandatory");
+ } else {
+ String opt = imp.getAttribute("optional");
+ optional = opt != null && opt.equalsIgnoreCase("true");
+
+ String agg = imp.getAttribute("aggregate");
+ aggregate = agg != null && agg.equalsIgnoreCase("true");
+
+ String original = "(&(objectClass=" + specification + ")(!(instance.name=" + getCompositeManager().getInstanceName() + ")))"; // Cannot import yourself
+ String filter = original;
+ String givenFilter = imp.getAttribute("filter");
+ if (givenFilter != null) {
+ filter = "(&" + filter + givenFilter + ")"; //NOPMD
+ }
+
+ String identitity = imp.getAttribute("id");
+
+ String scope = imp.getAttribute("scope");
+ BundleContext context = getCompositeManager().getGlobalContext(); // Get the default bundle context.
+ if (scope != null) {
+ if (scope.equalsIgnoreCase("global")) {
+ context = new PolicyServiceContext(getCompositeManager().getGlobalContext(), getCompositeManager().getParentServiceContext(), PolicyServiceContext.GLOBAL);
+ } else if (scope.equalsIgnoreCase("composite")) {
+ context = new PolicyServiceContext(getCompositeManager().getGlobalContext(), getCompositeManager().getParentServiceContext(), PolicyServiceContext.LOCAL);
+ } else if (scope.equalsIgnoreCase("composite+global")) {
+ context = new PolicyServiceContext(getCompositeManager().getGlobalContext(), getCompositeManager().getParentServiceContext(), PolicyServiceContext.LOCAL_AND_GLOBAL);
+ }
+ }
+
+ // Configure instance filter if available
+ if (confFilter != null && identitity != null && confFilter.get(identitity) != null) {
+ filter = "(&" + original + (String) confFilter.get(identitity) + ")";
+ }
+
+ Filter fil = null;
+ if (filter != null) {
+ try {
+ fil = getCompositeManager().getGlobalContext().createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("A required filter " + filter + " is malformed", e);
+ }
+ }
+
+ Comparator cmp = DependencyMetadataHelper.getComparator(imp, getCompositeManager().getGlobalContext());
+ Class spec = DependencyMetadataHelper.loadSpecification(specification, getCompositeManager().getGlobalContext());
+ int policy = DependencyMetadataHelper.getPolicy(imp);
+
+ ServiceImporter importer = new ServiceImporter(spec, fil, aggregate, optional, cmp, policy, context, identitity, this);
+ m_importers.add(importer);
+
+ String sources = imp.getAttribute("context-source");
+ if (sources != null) {
+ SourceManager source = new SourceManager(sources, filter, importer, getCompositeManager());
+ if (m_sources == null) {
+ m_sources = new ArrayList(1);
+ }
+ m_sources.add(source);
+ }
+
+ }
+ }
+
+ /**
+ * Configure the handler.
+ * @param metadata : the metadata of the component
+ * @param conf : the instance configuration
+ * @throws ConfigurationException : the specification attribute is missing
+ * @see CompositeHandler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary conf) throws ConfigurationException {
+ Element[] services = metadata.getElements("subservice");
+ // Get instance filters
+ Dictionary confFilter = null;
+ if (conf.get("requires.filters") != null) {
+ confFilter = (Dictionary) conf.get("requires.filters");
+ }
+
+ for (int i = 0; i < services.length; i++) {
+ String action = services[i].getAttribute("action");
+ if (action == null) {
+ throw new ConfigurationException("The action attribute must be set to 'instantiate' or 'import'");
+ } else if ("instantiate".equalsIgnoreCase(action)) {
+ createServiceInstance(services[i], conf);
+ } else if ("import".equalsIgnoreCase(action)) {
+ createServiceImport(services[i], confFilter);
+ } else {
+ throw new ConfigurationException("Unknown action : " + action);
+ }
+ }
+
+ m_description = new ServiceInstantiatorDescription(this, m_instances, m_importers);
+ }
+
+ /**
+ * Start the service instantiator handler.
+ * Start all created service instance.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#start()
+ */
+ public void start() {
+ for (int i = 0; m_sources != null && i < m_sources.size(); i++) {
+ SourceManager source = (SourceManager) m_sources.get(i);
+ source.start();
+ }
+
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_importers.get(i);
+ imp.start();
+ }
+
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ inst.start();
+ }
+
+ isHandlerValid();
+ m_isStarted = true;
+ }
+
+ /**
+ * Check the handler validity.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#isValid()
+ */
+ private void isHandlerValid() {
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_importers.get(i);
+ if (imp.getState() != DependencyModel.RESOLVED) {
+ setValidity(false);
+ return;
+ }
+ }
+
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ if (inst.getState() != DependencyModel.RESOLVED) {
+ setValidity(false);
+ return;
+ }
+ }
+
+ setValidity(true);
+ }
+
+ /**
+ * Handler stop method.
+ * Stop all created service instance.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#stop()
+ */
+ public void stop() {
+ for (int i = 0; m_sources != null && i < m_sources.size(); i++) {
+ SourceManager source = (SourceManager) m_sources.get(i);
+ source.stop();
+ }
+
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ inst.stop();
+ }
+
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_importers.get(i);
+ imp.stop();
+ }
+
+ m_isStarted = false;
+ }
+
+ /**
+ * State change callback.
+ * This method is used to freeze the set of used provider if the static binding policy is used.
+ * @param newState : the new state of the underlying instance
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int newState) {
+ // If we are becoming valid and started, check if we need to freeze importers.
+ if (m_isStarted && newState == ComponentInstance.VALID) {
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_importers.get(i);
+ if (imp.getBindingPolicy() == DependencyModel.STATIC_BINDING_POLICY) {
+ imp.freeze();
+ }
+ }
+
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance imp = (SvcInstance) m_instances.get(i);
+ if (imp.getBindingPolicy() == DependencyModel.STATIC_BINDING_POLICY) {
+ imp.freeze();
+ }
+ }
+ }
+ }
+
+ /**
+ * An service instance becomes valid.
+ * @param dep : dependency becoming valid.
+ */
+ public void validate(DependencyModel dep) {
+ if (!getValidity()) {
+ isHandlerValid();
+ }
+ }
+
+ /**
+ * A service instance becomes invalid.
+ * @param dep : dependency becoming valid.
+ */
+ public void invalidate(DependencyModel dep) {
+ if (getValidity()) {
+ isHandlerValid();
+ }
+ }
+
+ /**
+ * Get the service instantiator handler description.
+ * @return the description
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ public List getInstances() {
+ return m_instances;
+ }
+
+ public List getRequirements() {
+ return m_importers;
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java
new file mode 100644
index 0000000..36ac5a9
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java
@@ -0,0 +1,326 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.PolicyServiceContext;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Import a service form the parent to the internal service registry.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceImporter extends DependencyModel {
+
+ /**
+ * Reference on the handler.
+ */
+ private ServiceDependencyHandler m_handler;
+
+ private final class Record {
+ /**
+ * External Reference.
+ */
+ private ServiceReference m_ref;
+
+ /**
+ * Internal Registration.
+ */
+ private ServiceRegistration m_reg;
+
+ /**
+ * Exposed Object.
+ */
+ private Object m_svcObject;
+
+ /**
+ * Constructor.
+ * @param ref : service reference.
+ */
+ protected Record(ServiceReference ref) {
+ m_ref = ref;
+ }
+
+ /**
+ * Register the current import.
+ */
+ private void register() {
+ if (m_reg != null) {
+ m_reg.unregister();
+ }
+ m_svcObject = getService(m_ref);
+ m_reg = m_handler.getCompositeManager().getServiceContext()
+ .registerService(getSpecification().getName(), m_svcObject, getProps(m_ref));
+ }
+
+ /**
+ * Update the current import.
+ */
+ private void update() {
+ if (m_reg != null) {
+ m_reg.setProperties(getProps(m_ref));
+ }
+ }
+
+ /**
+ * Unregister and release the current import.
+ */
+ private void dispose() {
+ if (m_reg != null) {
+ m_reg.unregister();
+ m_svcObject = null;
+ m_reg = null;
+ }
+ m_ref = null;
+ }
+
+ /**
+ * Test object equality.
+ * @param object : object to confront against the current object.
+ * @return true if the two objects are equals (same service reference).
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object object) {
+ if (object instanceof Record) {
+ Record rec = (Record) object;
+ return rec.m_ref == m_ref;
+ }
+ return false;
+ }
+
+ /**
+ * Hash code method.
+ * @return the hash code by calling the parent method.
+ */
+ public int hashCode() {
+ return super.hashCode();
+ }
+ }
+
+ /**
+ * List of managed records.
+ */
+ private List/*<Record>*/m_records = new ArrayList()/* <Record> */;
+
+ /**
+ * Requirement Id.
+ */
+ private String m_id;
+
+ /**
+ * Is this requirement attached to a service-level requirement.
+ */
+ private boolean m_specLevelReq;
+
+ /**
+ * Is the set of used provider frozen ?
+ */
+ private boolean m_isFrozen;
+
+ /**
+ * Constructor.
+ *
+ * @param specification : targeted specification
+ * @param filter : LDAP filter
+ * @param multiple : should the importer imports several services ?
+ * @param optional : is the import optional ?
+ * @param cmp : comparator to use for the tracking
+ * @param policy : resolving policy
+ * @param context : bundle context to use for the tracking (can be a servie context)
+ * @param identitity : requirement id (may be null)
+ * @param handler : handler
+ */
+ public ServiceImporter(Class specification, Filter filter, boolean multiple, boolean optional, Comparator cmp, int policy, BundleContext context, String identitity
+ , ServiceDependencyHandler handler) {
+ super(specification, multiple, optional, filter, cmp, policy, context, handler, handler.getCompositeManager());
+
+ this.m_handler = handler;
+
+ if (m_id == null) {
+ m_id = super.getSpecification().getName();
+ } else {
+ m_id = identitity;
+ }
+
+ }
+
+ /**
+ * Get the properties for the exposed service from the given reference.
+ *
+ * @param ref : the reference.
+ * @return the property dictionary
+ */
+ private static Dictionary getProps(ServiceReference ref) {
+ Properties prop = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ prop.put(keys[i], ref.getProperty(keys[i]));
+ }
+ return prop;
+ }
+
+ /**
+ * Freeze the set of used provider.
+ * This method allow to fix the set of provider when the static binding policy is used.
+ */
+ public void freeze() {
+ m_isFrozen = true;
+ }
+
+ /**
+ * Unfreezes.
+ */
+ public void unfreeze() {
+ m_isFrozen = false;
+ }
+
+ public boolean isFrozen() {
+ return m_isFrozen;
+ }
+
+ /**
+ * Stop the management of the import.
+ */
+ public void stop() {
+
+ super.stop();
+
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.dispose();
+ }
+
+ m_records.clear();
+
+ }
+
+ /**
+ * Get the record list using the given reference.
+ *
+ * @param ref : the reference
+ * @return the list containing all record using the given reference
+ */
+ private List/* <Record> */getRecordsByRef(ServiceReference ref) {
+ List list = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ if (rec.m_ref == ref) {
+ list.add(rec);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Build the list of imported service provider.
+ * @return the list of all imported services.
+ */
+ public List getProviders() {
+ List list = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ list.add((((Record) m_records.get(i)).m_ref).getProperty("instance.name"));
+ }
+ return list;
+ }
+
+ /**
+ * Set that this dependency is a service level dependency.
+ * This forces the scoping policy to be STRICT.
+ */
+ public void setServiceLevelDependency() {
+ m_specLevelReq = true;
+ PolicyServiceContext context = new PolicyServiceContext(m_handler.getCompositeManager().getGlobalContext(), m_handler.getCompositeManager().getParentServiceContext(), PolicyServiceContext.LOCAL);
+ setBundleContext(context);
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public boolean isServiceLevelRequirement() {
+ return m_specLevelReq;
+ }
+
+ /**
+ * On Dependency Reconfiguration notification method.
+ * @param departs : leaving service references.
+ * @param arrivals : new injected service references.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[])
+ */
+ public void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals) {
+ for (int i = 0; departs != null && i < departs.length; i++) {
+ onServiceDeparture(departs[i]);
+ }
+
+ for (int i = 0; arrivals != null && i < arrivals.length; i++) {
+ onServiceArrival(arrivals[i]);
+ }
+ }
+
+ /**
+ * A new service is injected by the tracker.
+ * This method create a 'Record' and register it.
+ * @param ref : new service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceArrival(ServiceReference ref) {
+ Record rec = new Record(ref);
+ m_records.add(rec);
+ // Always register the reference, as the method is call only when needed.
+ rec.register();
+ }
+
+ /**
+ * A used service disappears.
+ * This method find the implicated 'Record', dispose it and remove it from the list.
+ * @param ref : leaving service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceDeparture(ServiceReference ref) {
+ List list = getRecordsByRef(ref);
+ for (int i = 0; i < list.size(); i++) { // Stop the implied record
+ Record rec = (Record) list.get(i);
+ rec.dispose();
+ }
+ m_records.removeAll(list);
+ }
+
+ /**
+ * A used service is modified.
+ * @param ref : modified service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceModification(ServiceReference ref) {
+ List list = getRecordsByRef(ref);
+ for (int i = 0; i < list.size(); i++) { // Stop the implied record
+ Record rec = (Record) list.get(i);
+ rec.update();
+ }
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java
new file mode 100644
index 0000000..2125153
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java
@@ -0,0 +1,117 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Description of the Service Creator Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceInstantiatorDescription extends HandlerDescription {
+
+ /**
+ * List of managed service instances.
+ */
+ private List m_instances;
+
+ /**
+ * List of exports.
+ */
+ private List m_imports;
+
+ /**
+ * Constructor.
+ *
+ * @param handler : composite handler
+ * @param insts : list of service instances
+ * @param imps : list of service importers
+ */
+ public ServiceInstantiatorDescription(CompositeHandler handler, List insts, List imps) {
+ super(handler);
+ m_instances = insts;
+ m_imports = imps;
+ }
+
+ /**
+ * Build service instantiator handler description.
+ * @return the handler description
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element services = super.getHandlerInfo();
+ for (int i = 0; i < m_imports.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_imports.get(i);
+ Element impo = new Element("Requires", "");
+ impo.addAttribute(new Attribute("Specification", imp.getSpecification().getName()));
+ if (imp.getFilter() != null) {
+ impo.addAttribute(new Attribute("Filter", imp.getFilter()));
+ }
+ if (imp.getState() == DependencyModel.RESOLVED) {
+ impo.addAttribute(new Attribute("State", "resolved"));
+ for (int j = 0; j < imp.getProviders().size(); j++) {
+ Element prov = new Element("Provider", "");
+ prov.addAttribute(new Attribute("name", (String) imp.getProviders().get(j)));
+ impo.addElement(prov);
+ }
+ } else {
+ impo.addAttribute(new Attribute("State", "unresolved"));
+ }
+ services.addElement(impo);
+ }
+
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ Element service = new Element("Service", "");
+ service.addAttribute(new Attribute("Specification", inst.getServiceSpecification()));
+ String state = "unresolved";
+ if (inst.getState() == DependencyModel.RESOLVED) {
+ state = "resolved";
+ }
+ service.addAttribute(new Attribute("State", state));
+ Map map = inst.getMatchingFactories();
+ Set keys = map.keySet();
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference ref = (ServiceReference) iterator.next();
+ Object object = map.get(ref);
+ if (object != null) {
+ Element fact = new Element("Factory", "");
+ fact.addAttribute(new Attribute("Name", ((ComponentInstance) object).getFactory().getName()));
+ service.addElement(fact);
+ }
+ }
+ services.addElement(service);
+ }
+ return services;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
new file mode 100644
index 0000000..d61d347
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
@@ -0,0 +1,295 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Manage a service instantiation. This service create component instance providing the required service specification.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SvcInstance extends DependencyModel {
+
+ /**
+ * Configuration to push to the instance.
+ */
+ private Dictionary m_configuration;
+
+ /**
+ * Handler creating the service instance.
+ */
+ private ServiceDependencyHandler m_handler;
+
+ /**
+ * Map of matching factories Service Reference => instance or null (null if the service reference is not actually used).
+ */
+ private Map /* <ServiceReference, Instance> */m_factories = new HashMap();
+
+ /**
+ * Required specification.
+ */
+ private String m_specification;
+
+ /**
+ * Is the service provider frozen ? (Is used for static biding policy)
+ */
+ private boolean m_isFrozen;
+
+ /**
+ * Constructor.
+ * @param handler : the handler.
+ * @param spec : required specification.
+ * @param conf : instance configuration.
+ * @param isAgg : is the service instance an aggregate service ?
+ * @param isOpt : is the service instance optional ?
+ * @param filt : LDAP filter
+ * @param cmp : comparator to use for the tracking
+ * @param policy : binding policy
+ * @throws ConfigurationException : an attribute cannot be parsed correctly, or is incorrect.
+ */
+ public SvcInstance(ServiceDependencyHandler handler, String spec, Dictionary conf, boolean isAgg, boolean isOpt, Filter filt, Comparator cmp, int policy) throws ConfigurationException {
+ super(Factory.class, isAgg, isOpt, filt, cmp, policy, null, handler, handler.getCompositeManager());
+
+ m_specification = spec;
+
+ m_handler = handler;
+ setBundleContext(m_handler.getCompositeManager().getServiceContext());
+
+ m_configuration = conf;
+ }
+
+ /**
+ * Stop the service instance.
+ */
+ public void stop() {
+ super.stop();
+
+ Set keys = m_factories.keySet();
+ Iterator iterator = keys.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference ref = (ServiceReference) iterator.next();
+ Object object = m_factories.get(ref);
+ if (object != null) {
+ m_handler.info("Dispose a service instance when stopping the handler " + ((ComponentInstance) object).getInstanceName());
+ ((ComponentInstance) object).dispose();
+ }
+ }
+
+ m_factories.clear();
+
+ }
+
+ public boolean isFrozen() {
+ return m_isFrozen;
+ }
+
+ /**
+ * Freeze the set of used provider.
+ * This method is when the static binding policy is applied.
+ */
+ public void freeze() {
+ m_isFrozen = true;
+ }
+
+ /**
+ * Unfreezes.
+ */
+ public void unfreeze() {
+ m_isFrozen = false;
+ }
+
+
+ /**
+ * Create an instance for the given reference. The instance is not added inside the map.
+ * @param factory : the factory from which we need to create the instance.
+ * @return the created component instance.
+ * @throws ConfigurationException : the instance cannot be configured correctly.
+ * @throws MissingHandlerException : the factory is invalid.
+ * @throws UnacceptableConfiguration : the given configuration is invalid for the given factory.
+ */
+ private ComponentInstance createInstance(Factory factory) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Recreate the configuration to avoid sharing.
+ Properties props = new Properties();
+ Enumeration keys = m_configuration.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ props.put(key, m_configuration.get(key));
+ }
+ ComponentInstance instance = null;
+ instance = factory.createComponentInstance(props);
+ m_handler.info("Creation of a service instance " + instance.getInstanceName());
+ return instance;
+ }
+
+ /**
+ * Does the service instance match with the given factory ?
+ * @param fact : the factory to test.
+ * @return true if the factory match, false otherwise.
+ */
+ public boolean match(ServiceReference fact) {
+ // Check if the factory can provide the specification
+ ComponentTypeDescription desc = (ComponentTypeDescription) fact.getProperty("component.description");
+ if (desc == null) {
+ return false; // No component type description.
+ }
+
+ String[] provides = desc.getprovidedServiceSpecification();
+ for (int i = 0; provides != null && i < provides.length; i++) {
+ if (provides[i].equals(m_specification)) {
+ // Check that the factory needs every properties contained in
+ // the configuration
+ PropertyDescription[] props = desc.getProperties();
+ Properties conf = new Properties();
+ Enumeration keys = m_configuration.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (!containsProperty(key, props)) { return false; }
+ conf.put(key, m_configuration.get(key));
+ }
+
+ Factory factory = (Factory) getService(fact);
+ return factory.isAcceptable(conf);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does the factory support the given property ? This method check if the property is contained in the given property description array.
+ * @param name : name of the property
+ * @param props : list of property description
+ * @return true if the factory support this property
+ */
+ private boolean containsProperty(String name, org.apache.felix.ipojo.architecture.PropertyDescription[] props) {
+ for (int i = 0; props != null && i < props.length; i++) {
+ if (props[i].getName().equalsIgnoreCase(name)) { return true; }
+ }
+ if (name.equalsIgnoreCase("name")) { return true; } // Skip the name property
+ return false;
+ }
+
+ /**
+ * Get the required specification.
+ * @return the required specification.
+ */
+ public String getServiceSpecification() {
+ return m_specification;
+ }
+
+ /**
+ * Get the map of used references [reference, component instance].
+ * @return the map of used references.
+ */
+ protected Map getMatchingFactories() {
+ return m_factories;
+ }
+
+ /**
+ * On Dependency Reconfiguration notification method.
+ * @param departs : leaving service references.
+ * @param arrivals : new injected service references.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[])
+ */
+ public void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals) {
+ for (int i = 0; departs != null && i < departs.length; i++) {
+ onServiceDeparture(departs[i]);
+ }
+
+ for (int i = 0; arrivals != null && i < arrivals.length; i++) {
+ onServiceArrival(arrivals[i]);
+ }
+ }
+
+ /**
+ * A new service is injected.
+ * This method create the sub-service instance in the composite.
+ * @param ref : service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceArrival(ServiceReference ref) {
+ // The given factory matches.
+ try {
+ Factory fact = (Factory) getService(ref);
+ if (m_factories.get(ref) == null) {
+ ComponentInstance instance = createInstance(fact);
+ m_factories.put(ref, instance);
+ } else {
+ m_handler
+ .info("An arriving factory is already used, ignore the creation : "
+ + fact.getName());
+ }
+
+ } catch (UnacceptableConfiguration e) {
+ m_handler.error("A matching factory refuses the actual configuration : " + e.getMessage());
+ m_handler.getCompositeManager().stop();
+ } catch (MissingHandlerException e) {
+ m_handler.error("A matching factory is no more valid : " + e.getMessage());
+ m_handler.getCompositeManager().stop();
+ } catch (ConfigurationException e) {
+ m_handler.error("A matching configuration is refused by the instance : " + e.getMessage());
+ m_handler.getCompositeManager().stop();
+ }
+
+ }
+
+
+ /**
+ * A used service is leaving.
+ * This method dispose the created instance.
+ * @param ref : leaving service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceDeparture(ServiceReference ref) {
+ // Remove the reference is contained
+ Object instance = m_factories.remove(ref);
+ if (instance != null) {
+ m_handler.info("Dispose the instance (departure of the factory) "
+ + ((ComponentInstance) instance).getInstanceName());
+ ((ComponentInstance) instance).dispose();
+ }
+ }
+
+ /**
+ * A factory is modified. This should not happen.
+ * @param arg0 the service reference
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceModification(ServiceReference arg0) {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java
new file mode 100644
index 0000000..801b595
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java
@@ -0,0 +1,44 @@
+/*
+ * 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.composite.service.provides;
+
+/**
+ * Exception occurs when a composition error occurs.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositionException extends Exception {
+ //TODO consider removing this class to use configuration exception.
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = -3063353267573738105L;
+
+ /**
+ * Constructor.
+ * @param message a message.
+ */
+ public CompositionException(String message) {
+ this(message, null);
+ }
+
+ public CompositionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java
new file mode 100644
index 0000000..39c497d
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java
@@ -0,0 +1,361 @@
+/*
+ * 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.composite.service.provides;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.manipulation.Manipulator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Check and build a composition, i.e. a POJO containing the composition.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositionMetadata {
+
+ /**
+ * Implemented composition.
+ */
+ private SpecificationMetadata m_specification;
+
+ /**
+ * Name of the composition.
+ */
+ private String m_name;
+
+ /**
+ * Bundle Context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Manipulation Metadata.
+ */
+ private Element m_manipulation;
+
+ /**
+ * Reference on the handler.
+ */
+ private ProvidedServiceHandler m_handler;
+
+ /**
+ * List of Mappings.
+ */
+ private List m_mappings = new ArrayList();
+
+ /**
+ * Constructor.
+ * @param context : bundle context
+ * @param description : 'provides' element
+ * @param psh : parent handler
+ * @param name : name of the composition.
+ */
+ public CompositionMetadata(BundleContext context, Element description, ProvidedServiceHandler psh, String name) {
+ m_context = context;
+ m_handler = psh;
+ // Get the composition name
+ m_name = description.getAttribute("specification") + name;
+
+ // Get implemented service specification
+ String spec = description.getAttribute("specification");
+ m_specification = new SpecificationMetadata(spec, m_context, false, false, m_handler);
+
+ Element[] mappings = description.getElements("delegation");
+ for (int i = 0; mappings != null && i < mappings.length; i++) {
+ String methodName = mappings[i].getAttribute("method");
+ MethodMetadata method = m_specification.getMethodByName(methodName);
+ if (method == null) {
+ m_handler.error("The method " + methodName + " does not exist in the specicifation " + spec);
+ return;
+ }
+
+ if (mappings[i].getAttribute("policy").equalsIgnoreCase("All")) {
+ method.setAllPolicy();
+ }
+ }
+ }
+
+ protected BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public SpecificationMetadata getSpecificationMetadata() {
+ return m_specification;
+ }
+
+ /**
+ * Build Available Mappings.
+ * @throws CompositionException : a factory is not available, the composition cannot be checked.
+ */
+ private void buildAvailableMappingList() throws CompositionException {
+ int index = 0;
+
+ for (int i = 0; i < m_handler.getInstanceType().size(); i++) {
+ String type = (String) m_handler.getInstanceType().get(i);
+ try {
+ ServiceReference[] refs = m_context.getServiceReferences(Factory.class.getName(), "(factory.name=" + type + ")");
+ if (refs == null) {
+ m_handler.error("The factory " + type + " is not available, cannot check the composition");
+ throw new CompositionException("The factory " + type + " needs to be available to check the composition");
+ } else {
+ String className = (String) refs[0].getProperty("component.class");
+ Class impl = m_context.getBundle().loadClass(className);
+ SpecificationMetadata spec = new SpecificationMetadata(impl, type, m_handler);
+ FieldMetadata field = new FieldMetadata(spec);
+ field.setName("_field" + index);
+ Mapping map = new Mapping(spec, field);
+ m_mappings.add(map);
+ index++;
+ }
+ } catch (InvalidSyntaxException e) {
+ m_handler.error("A LDAP filter is not valid : " + e.getMessage());
+ } catch (ClassNotFoundException e) {
+ m_handler.error("The implementation class of a component cannot be loaded : " + e.getMessage());
+ }
+ }
+
+ for (int i = 0; i < m_handler.getSpecifications().size(); i++) {
+ SpecificationMetadata spec = (SpecificationMetadata) m_handler.getSpecifications().get(i);
+ FieldMetadata field = new FieldMetadata(spec);
+ field.setName("_field" + index);
+ if (spec.isOptional()) {
+ field.setOptional(true);
+ }
+ if (spec.isAggregate()) {
+ field.setAggregate(true);
+ }
+ Mapping map = new Mapping(spec, field);
+ m_mappings.add(map);
+ index++;
+ }
+ }
+
+ /**
+ * Build the delegation mapping.
+ * @throws CompositionException : occurs when the mapping cannot be inferred correctly
+ */
+ protected void buildMapping() throws CompositionException {
+ buildAvailableMappingList();
+
+ // Dependency closure is OK, now look for method delegation
+ Map/* <MethodMetadata, Mapping> */svcMethods = new HashMap();
+ Map/* <MethodMetadata, Mapping> */instMethods = new HashMap();
+
+ for (int i = 0; i < m_mappings.size(); i++) {
+ Mapping map = (Mapping) m_mappings.get(i);
+ SpecificationMetadata spec = map.getSpecification();
+ for (int j = 0; j < spec.getMethods().size(); j++) {
+ MethodMetadata method = (MethodMetadata) spec.getMethods().get(j);
+ if (spec.isInterface()) {
+ svcMethods.put(method, map);
+ } else {
+ instMethods.put(method, map);
+ }
+ }
+ }
+
+ // For each needed method, search if available and store the mapping
+ for (int j = 0; j < m_specification.getMethods().size(); j++) {
+ MethodMetadata method = (MethodMetadata) m_specification.getMethods().get(j);
+ Set keys = instMethods.keySet(); // Look first in methods contained in the glue code.
+ Iterator iterator = keys.iterator();
+ boolean found = false;
+ while (iterator.hasNext() & !found) {
+ MethodMetadata met = (MethodMetadata) iterator.next();
+ if (met.equals(method)) {
+ found = true;
+ FieldMetadata field = ((Mapping) instMethods.get(met)).getField();
+ field.setUseful(true);
+ method.setDelegation(field);
+ }
+ }
+ if (!found) { // If not found looks inside method contained in services.
+ keys = svcMethods.keySet(); // Look first in methods contained in the glue code
+ iterator = keys.iterator();
+ while (!found && iterator.hasNext()) {
+ MethodMetadata met = (MethodMetadata) iterator.next();
+ if (met.equals(method)) {
+ found = true;
+ FieldMetadata field = ((Mapping) svcMethods.get(met)).getField();
+ field.setUseful(true);
+ method.setDelegation(field);
+ // Test optional
+ if (field.isOptional() && !method.throwsUnsupportedOperationException()) {
+ m_handler.warn("The method " + method.getMethod().getName() + " could not be provided correctly : the specification " + field.getSpecification().getName() + " is optional");
+ }
+ }
+ }
+ }
+ if (!found) { throw new CompositionException("Inconsistent composition - the method " + method.getMethod() + " could not be delegated"); }
+ }
+ }
+
+ /**
+ * Build a service implementation.
+ * @return the byte[] of the POJO.
+ */
+ protected byte[] buildPOJO() {
+ Class clazz = null;
+ try {
+ clazz = getBundleContext().getBundle().loadClass(m_specification.getName());
+ } catch (ClassNotFoundException e1) {
+ // The class has already be loaded.
+ return null;
+ }
+ byte[] pojo = POJOWriter.dump(clazz, m_name, getFieldList(), getMethodList(), m_handler);
+ Manipulator manipulator = new Manipulator(this.getClass().getClassLoader());
+ try {
+ manipulator.prepare(pojo);
+ byte[] newclazz = manipulator.manipulate(pojo);
+ m_manipulation = manipulator.getManipulationMetadata();
+ return newclazz;
+ } catch (IOException e) {
+ m_handler.error("An error occurs during the composite implementation creation : " + e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * Build service implementation metadata.
+ * @param name : name of the future instance (used to avoid cycle)
+ * @return Component Type metadata.
+ */
+ protected Element buildMetadata(String name) {
+ Element elem = new Element("component", "");
+ Attribute className = new Attribute("classname", m_name);
+ Attribute factory = new Attribute("public", "false");
+ elem.addAttribute(className);
+ elem.addAttribute(factory);
+
+ // Add architecture for debug
+ elem.addAttribute(new Attribute("architecture", "true"));
+
+ // Provides
+ Element provides = new Element("provides", "");
+ provides.addAttribute(new Attribute("specification", m_specification.getName()));
+ elem.addElement(provides);
+
+ // Dependencies
+ List fields = getFieldList();
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful() && field.getSpecification().isInterface()) {
+ Element dep = new Element("requires", "");
+ dep.addAttribute(new Attribute("field", field.getName()));
+ dep.addAttribute(new Attribute("scope", "composite"));
+ dep.addAttribute(new Attribute("proxy", "false"));
+ if (field.getSpecification().isOptional()) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ dep.addAttribute(new Attribute("filter", "(!(instance.name=" + name + "))"));
+ elem.addElement(dep);
+ }
+ }
+
+ Element properties = new Element("properties", "");
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful() && !field.getSpecification().isInterface()) {
+ Element prop = new Element("Property", "");
+ prop.addAttribute(new Attribute("field", field.getName()));
+ properties.addElement(prop);
+ }
+ }
+ if (properties.getElements().length != 0) {
+ elem.addElement(properties);
+ }
+
+ // Insert information to metadata
+ elem.addElement(m_manipulation);
+
+ return elem;
+ }
+
+ /**
+ * Get the field list to use for the delegation.
+ * @return the field list.
+ */
+ public List getFieldList() {
+ List list = new ArrayList();
+ for (int i = 0; i < m_mappings.size(); i++) {
+ Mapping map = (Mapping) m_mappings.get(i);
+ list.add(map.getField());
+ }
+ return list;
+ }
+
+ /**
+ * Get the method list contained in the implemented specification.
+ * @return the List of implemented method.
+ */
+ private List getMethodList() {
+ return m_specification.getMethods();
+ }
+
+ /**
+ * Store links between Field and pointed Specification.
+ */
+ private class Mapping {
+
+ /**
+ * Specification.
+ */
+ private SpecificationMetadata m_spec;
+
+ /**
+ * Field.
+ */
+ private FieldMetadata m_field;
+
+ /**
+ * Constructor.
+ * @param spec : specification metadata.
+ * @param field : the field.
+ */
+ public Mapping(SpecificationMetadata spec, FieldMetadata field) {
+ m_spec = spec;
+ m_field = field;
+ }
+
+ public SpecificationMetadata getSpecification() {
+ return m_spec;
+ }
+
+ public FieldMetadata getField() {
+ return m_field;
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java
new file mode 100644
index 0000000..4df41a8
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java
@@ -0,0 +1,105 @@
+/*
+ * 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.composite.service.provides;
+
+/**
+ * Field used inside a composition.
+ * This class contains all information useful for the generation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadata {
+
+ /**
+ * Name of the field.
+ */
+ private String m_name;
+
+ /**
+ * Is the field an array?
+ */
+ private boolean m_isAggregate = false;
+
+ /**
+ * Interface of the field.
+ */
+ private SpecificationMetadata m_specification;
+
+ /**
+ * Is the field useful in this composition.
+ */
+ private boolean m_isUseful;
+
+ /**
+ * Is the dependency for this field optional.
+ */
+ private boolean m_isOptional = false;
+
+ /**
+ * Constructor.
+ * @param specification : interface of the field.
+ */
+ public FieldMetadata(SpecificationMetadata specification) {
+ super();
+ this.m_specification = specification;
+ if (m_specification.isAggregate()) {
+ m_isAggregate = true;
+ }
+ }
+
+ public boolean isAggregate() {
+ return m_isAggregate;
+ }
+
+ public void setAggregate(boolean aggregate) {
+ m_isAggregate = aggregate;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ public SpecificationMetadata getSpecification() {
+ return m_specification;
+ }
+
+ public void setSpecification(SpecificationMetadata specification) {
+ this.m_specification = specification;
+ }
+
+ public boolean isUseful() {
+ return m_isUseful;
+ }
+
+ public void setUseful(boolean useful) {
+ m_isUseful = useful;
+ }
+
+ public boolean isOptional() {
+ return m_isOptional;
+ }
+
+ public void setOptional(boolean opt) {
+ m_isOptional = opt;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java
new file mode 100644
index 0000000..510514e
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java
@@ -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.felix.ipojo.composite.service.provides;
+
+import java.lang.reflect.Method;
+
+/**
+ * Information on Method for the composition.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadata {
+
+ /**
+ * ONE POLICY.
+ */
+ public static final int ONE_POLICY = 1;
+
+ /**
+ * ALL POLICY.
+ */
+ public static final int ALL_POLICY = 2;
+
+ /**
+ * Method Object.
+ */
+ private Method m_method;
+
+ /**
+ * Delegation field.
+ */
+ private FieldMetadata m_delegation;
+
+ /**
+ * Delegation policy (default = ONE).
+ */
+ private int m_policy = ONE_POLICY;
+
+ /**
+ * Constructor.
+ * @param method : method object.
+ */
+ public MethodMetadata(Method method) {
+ m_method = method;
+ }
+
+ public Method getMethod() {
+ return m_method;
+ }
+
+ public void setDelegation(FieldMetadata field) {
+ m_delegation = field;
+ }
+
+ public FieldMetadata getDelegation() {
+ return m_delegation;
+ }
+
+ /**
+ * Equals method.
+ * This method check if two MethodMetadata are equals or if the current MemethodMetadata is equals with a Method object.
+ * @param object : object.
+ * @return true if the current object and the given object are equals.
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object object) {
+ if (object instanceof MethodMetadata) {
+ Method met = ((MethodMetadata) object).getMethod();
+ return equals(met);
+ }
+
+ if (object instanceof Method) {
+ Method met = (Method) object;
+ if (! met.getName().equals(m_method.getName()) || met.getParameterTypes().length != m_method.getParameterTypes().length) {
+ return false;
+ }
+
+ for (int i = 0; i < m_method.getParameterTypes().length; i++) {
+ if (!m_method.getParameterTypes()[i].getName().equals(met.getParameterTypes()[i].getName())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Hash code method.
+ * @return the parent hash code.
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ public int getPolicy() {
+ return m_policy;
+ }
+
+ /**
+ * Activate the all policy for this method.
+ */
+ public void setAllPolicy() {
+ m_policy = ALL_POLICY;
+ }
+
+ /**
+ * Check if the method can throw UnsupportedOperationException.
+ * @return true if the method has declared the UnsupportedOperationException.
+ */
+ protected boolean throwsUnsupportedOperationException() {
+ for (int i = 0; i < m_method.getExceptionTypes().length; i++) {
+ if (m_method.getExceptionTypes()[i].getName().equals(UnsupportedOperationException.class.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/POJOWriter.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/POJOWriter.java
new file mode 100644
index 0000000..ffca9c8
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/POJOWriter.java
@@ -0,0 +1,323 @@
+/*
+ * 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.composite.service.provides;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.felix.ipojo.Handler;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Create the Proxy class.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class POJOWriter implements Opcodes {
+
+ //TODO : merge this class with another class only static methods.
+
+ /**
+ * Create a class.
+ * @param cw : class writer
+ * @param className : class name
+ * @param spec : implemented specification
+ */
+ private static void createClass(ClassWriter cw, String className, String spec) {
+ // Create the class
+ cw.visit(V1_2, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", new String[] { spec.replace('.', '/') });
+ }
+
+ /**
+ * Inject field in the current class.
+ * @param cw : class writer.
+ * @param fields : list of field to inject.
+ */
+ private static void injectFields(ClassWriter cw, List fields) {
+ // Inject fields
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful()) {
+ SpecificationMetadata spec = field.getSpecification();
+ String fieldName = field.getName();
+ String desc = "";
+ if (field.isAggregate()) {
+ desc = "[L" + spec.getName().replace('.', '/') + ";";
+ } else {
+ desc = "L" + spec.getName().replace('.', '/') + ";";
+ }
+
+ cw.visitField(Opcodes.ACC_PRIVATE, fieldName, desc, null, null);
+ }
+ }
+ }
+
+ /**
+ * Generates an empty constructor.
+ * this constructor just call the java.lang.Object constructor.
+ * @param cw class writer
+ */
+ private static void generateConstructor(ClassWriter cw) {
+ // Inject a constructor <INIT>()V
+ MethodVisitor cst = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ cst.visitVarInsn(ALOAD, 0);
+ cst.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ cst.visitInsn(RETURN);
+ cst.visitMaxs(0, 0);
+ cst.visitEnd();
+ }
+
+ /**
+ * Return the proxy 'classname' for the contract 'contractname' by delegating on available service.
+ * @param clazz : Specification class
+ * @param className : The class name to create
+ * @param fields : the list of fields on which delegate
+ * @param methods : the list of method on which delegate
+ * @param handler : handler object used to access the logger
+ * @return byte[] : the build class
+ */
+ public static byte[] dump(Class clazz, String className, List fields, List methods, Handler handler) {
+ Method[] itfmethods = clazz.getMethods();
+
+ // Create the class
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ className = className.replace('.', '/');
+ createClass(cw, className, clazz.getName());
+
+ // Inject fields inside the POJO
+ injectFields(cw, fields);
+
+ generateConstructor(cw);
+
+ for (int i = 0; i < itfmethods.length; ++i) {
+ Method method = itfmethods[i];
+
+ // Get the field for this method
+ // 1) find the MethodMetadata
+ FieldMetadata delegator = null; // field to delegate
+ MethodMetadata methodDelegator = null; // field to delegate
+ for (int j = 0; j < methods.size(); j++) {
+ MethodMetadata methodMeta = (MethodMetadata) methods.get(j);
+ if (methodMeta.equals(method)) {
+ delegator = methodMeta.getDelegation();
+ methodDelegator = methodMeta;
+ }
+ }
+
+ generateMethod(cw, className, methodDelegator, method, delegator, handler);
+
+ }
+
+ // End process
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ /**
+ * Generate on method.
+ * @param cw : class writer
+ * @param className : the current class name
+ * @param method : the method to generate
+ * @param sign : method signature to generate
+ * @param delegator : the field on which delegate
+ * @param handler : the handler (used to acess the logger)
+ */
+ private static void generateMethod(ClassWriter cw, String className, MethodMetadata method, Method sign, FieldMetadata delegator, Handler handler) {
+ String desc = Type.getMethodDescriptor(sign);
+ String name = sign.getName();
+ String[] exc = new String[sign.getExceptionTypes().length];
+ for (int i = 0; i < sign.getExceptionTypes().length; i++) {
+ exc[i] = Type.getType(sign.getExceptionTypes()[i]).getInternalName();
+ }
+
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, null, exc);
+
+ if (delegator.isOptional()) {
+ if (!delegator.isAggregate()) {
+ generateOptionalCase(mv, delegator, className);
+ }
+ if (delegator.isAggregate() /*&& method.getPolicy() == MethodMetadata.ONE_POLICY*/) {
+ generateOptionalAggregateCase(mv, delegator, className);
+ }
+ }
+
+ if (delegator.isAggregate()) {
+ if (method.getPolicy() == MethodMetadata.ONE_POLICY) {
+ // Aggregate and One Policy
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ICONST_0); // Use the first one
+ mv.visitInsn(AALOAD);
+
+ loadArgs(mv, ACC_PUBLIC, Type.getArgumentTypes(desc));
+
+ // Invoke
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+
+ // Return
+ mv.visitInsn(Type.getReturnType(desc).getOpcode(Opcodes.IRETURN));
+
+ } else { // All policy
+ if (Type.getReturnType(desc).getSort() != Type.VOID) {
+ handler.error("All policy cannot be used on method which does not return void");
+ }
+
+ Type[] args = Type.getArgumentTypes(desc);
+ int index = args.length + 1;
+
+ // Init
+ mv.visitInsn(ICONST_0);
+ mv.visitVarInsn(ISTORE, index);
+ Label l1b = new Label();
+ mv.visitLabel(l1b);
+ Label l2b = new Label();
+ mv.visitJumpInsn(GOTO, l2b);
+
+ // Loop
+ Label l3b = new Label();
+ mv.visitLabel(l3b);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitVarInsn(ILOAD, index);
+ mv.visitInsn(AALOAD);
+
+ loadArgs(mv, ACC_PUBLIC, Type.getArgumentTypes(desc));
+
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+
+ Label l4b = new Label();
+ mv.visitLabel(l4b);
+ mv.visitIincInsn(index, 1); // i++;
+
+ // Condition
+ mv.visitLabel(l2b);
+ mv.visitVarInsn(ILOAD, index);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitJumpInsn(IF_ICMPLT, l3b);
+
+ Label l5b = new Label();
+ mv.visitLabel(l5b);
+ mv.visitInsn(RETURN);
+ }
+ } else {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+
+ loadArgs(mv, ACC_PUBLIC, Type.getArgumentTypes(desc));
+
+ // Invoke
+ if (delegator.getSpecification().isInterface()) {
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+ } else {
+ mv.visitMethodInsn(INVOKEVIRTUAL, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+ }
+
+ // Return
+ mv.visitInsn(Type.getReturnType(desc).getOpcode(IRETURN));
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate Optional Case for aggregate field.
+ * @param mv : method visitor
+ * @param delegator : Field on which delegate
+ * @param className : current class name
+ */
+ private static void generateOptionalAggregateCase(MethodVisitor mv, FieldMetadata delegator, String className) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ARRAYLENGTH);
+ Label l1a = new Label();
+ mv.visitJumpInsn(IFNE, l1a);
+ Label l2a = new Label();
+ mv.visitLabel(l2a);
+ mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn("Operation not supported");
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(l1a);
+ }
+
+ /**
+ * Generate Optional case for non aggregate fields.
+ *
+ * @param mv : the method visitor
+ * @param delegator : the field on which delegate.
+ * @param className : the name of the current class.
+ */
+ private static void generateOptionalCase(MethodVisitor mv, FieldMetadata delegator, String className) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitTypeInsn(INSTANCEOF, "org/apache/felix/ipojo/Nullable");
+ Label end = new Label();
+ mv.visitJumpInsn(IFEQ, end);
+ Label begin = new Label();
+ mv.visitLabel(begin);
+ mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn("Operation not supported");
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(end);
+ }
+
+ /**
+ * Load on stack the method arguments.
+ * @param mv method visitor
+ * @param access access level of the method
+ * @param args argument types array
+ */
+ private static void loadArgs(MethodVisitor mv, int access, Type[] args) {
+ int i = 0;
+ int j = args.length;
+ int k = getArgIndex(access, args, i);
+ for (int l = 0; l < j; l++) {
+ Type type = args[i + l];
+ mv.visitVarInsn(type.getOpcode(ILOAD), k);
+ k += type.getSize();
+ }
+ }
+
+ /**
+ * Gets the index of the argument 'i'.
+ * This method manages double-spaces.
+ * @param access method access (mostly public)
+ * @param args argument type array
+ * @param i wanted index
+ * @return the real index
+ */
+ private static int getArgIndex(int access, Type[] args, int i) {
+ int j = (access & 8) != 0 ? 0 : 1;
+ for (int k = 0; k < i; k++) {
+ j += args[k].getSize();
+ }
+ return j;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java
new file mode 100644
index 0000000..05eb854
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java
@@ -0,0 +1,238 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.apache.felix.ipojo.composite.instance.InstanceHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyMetadataHelper;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Composite Provided Service.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedService implements DependencyStateListener {
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Composition Model.
+ */
+ private CompositionMetadata m_composition;
+
+ /**
+ * Internal context.
+ */
+ private ServiceContext m_scope;
+
+ /**
+ * External context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Created Factory.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Created Instance.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Exporter.
+ */
+ private ServiceExporter m_exports;
+
+ /**
+ * Created instance name.
+ */
+ private String m_instanceName;
+
+ /**
+ * Constructor.
+ * The delegation mapping is infers in this method.
+ * @param handler : the handler.
+ * @param element : 'provides' element.
+ * @param name : name of this provided service.
+ */
+ public ProvidedService(ProvidedServiceHandler handler, Element element, String name) {
+ m_manager = handler.getCompositeManager();
+ m_scope = m_manager.getServiceContext();
+ m_context = m_manager.getContext();
+ m_composition = new CompositionMetadata(m_manager.getContext(), element, handler, name);
+ }
+
+ /**
+ * Start method.
+ * Build service implementation type, factory and instance.
+ * @throws CompositionException if a consistent mapping cannot be discovered.
+ */
+ public void start() throws CompositionException {
+ m_composition.buildMapping();
+
+ m_instanceName = m_composition.getSpecificationMetadata().getName() + "Provider-Gen";
+ byte[] clazz = m_composition.buildPOJO();
+ Element metadata = m_composition.buildMetadata(m_instanceName);
+
+ // Create the factory
+ try {
+ m_factory = new ComponentFactory(m_context, clazz, metadata);
+ m_factory.setUseFactoryClassloader(true);
+ m_factory.start();
+ } catch (ConfigurationException e) {
+ // Should not happen.
+ m_manager.getFactory().getLogger().log(Logger.ERROR, "A factory cannot be created", e);
+ }
+
+ try {
+ Class spec = DependencyMetadataHelper.loadSpecification(m_composition.getSpecificationMetadata().getName(), m_context);
+ Filter filter = m_context.createFilter("(instance.name=" + m_instanceName + ")");
+ // Create the exports
+ m_exports = new ServiceExporter(spec, filter, false, false, null, DependencyModel.DYNAMIC_BINDING_POLICY, m_scope, m_context, this, m_manager);
+ } catch (InvalidSyntaxException e) {
+ throw new CompositionException("A provided service filter is invalid", e);
+ } catch (ConfigurationException e) {
+ throw new CompositionException("The class " + m_composition.getSpecificationMetadata().getName() + " cannot be loaded", e);
+ }
+ }
+
+ /**
+ * Stop the provided service.
+ * Kill the exporter, the instance and the factory.
+ */
+ public void stop() {
+ if (m_exports != null) {
+ m_exports.stop();
+ m_exports = null;
+ }
+ if (m_instance != null) {
+ m_instance.dispose();
+ m_instance = null;
+ }
+ if (m_factory != null) {
+ m_factory.stop();
+ m_factory = null;
+ }
+ }
+
+ protected CompositeManager getManager() {
+ return m_manager;
+ }
+
+ /**
+ * The exporter becomes valid.
+ * @param exporter : the exporter
+ */
+ public void validate(DependencyModel exporter) {
+ // Nothing to do.
+ }
+
+ /**
+ * The exporter becomes invalid.
+ * @param exporter : the exporter
+ */
+ public void invalidate(DependencyModel exporter) {
+ // Nothing to do.
+ }
+
+ /**
+ * Get an object from the given type.
+ * @param type : type
+ * @return an object from an instance of this type or null
+ */
+ private Object getObjectByType(String type) {
+ InstanceHandler handler = (InstanceHandler) m_manager.getCompositeHandler("org.apache.felix.ipojo.composite.instance.InstanceHandler");
+ Object pojo = handler.getObjectFromInstance(type);
+ if (pojo == null) {
+ m_manager.getFactory().getLogger().log(Logger.ERROR, "An instance object cannot be found for the type : " + type);
+ }
+ return pojo;
+ }
+
+ public String getSpecification() {
+ return m_composition.getSpecificationMetadata().getName();
+ }
+
+ /**
+ * Unregister the exposed service.
+ */
+ public void unregister() {
+ m_exports.stop();
+ }
+
+ /**
+ * Register the exposed service.
+ */
+ public void register() {
+ Properties props = new Properties();
+ props.put("instance.name", m_instanceName);
+ List fields = m_composition.getFieldList();
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful() && !field.getSpecification().isInterface()) {
+ String type = field.getSpecification().getComponentType();
+ Object pojo = getObjectByType(type);
+ props.put(field.getName(), pojo);
+ }
+ }
+
+ if (m_instance == null) {
+ // Else we have to create the instance
+ try {
+ m_instance = m_factory.createComponentInstance(props, m_manager.getServiceContext());
+ } catch (UnacceptableConfiguration e) {
+ throw new IllegalStateException("Cannot create the service implementation", e);
+ } catch (MissingHandlerException e) {
+ throw new IllegalStateException("Cannot create the service implementation", e);
+ } catch (ConfigurationException e) {
+ throw new IllegalStateException("Cannot create the service implementation", e);
+ }
+ } else {
+ // We have to reconfigure the instance in order to inject up to date glue component instance.
+ m_instance.reconfigure(props);
+ }
+
+ m_exports.start();
+ }
+
+ public boolean isRegistered() {
+ return m_exports.getState() == DependencyModel.RESOLVED;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java
new file mode 100644
index 0000000..fa47217
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java
@@ -0,0 +1,504 @@
+/*
+ * 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.composite.service.provides;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.HandlerManager;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.PolicyServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.composite.instance.InstanceHandler;
+import org.apache.felix.ipojo.composite.service.instantiator.ServiceDependencyHandler;
+import org.apache.felix.ipojo.composite.service.instantiator.ServiceImporter;
+import org.apache.felix.ipojo.composite.service.instantiator.SvcInstance;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.util.DependencyMetadataHelper;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Composite Provided Service Handler.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandler extends CompositeHandler implements DependencyStateListener {
+
+ /**
+ * External context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * List of "available" services in the internal context.
+ */
+ private List m_services = new ArrayList();
+
+ /**
+ * List of exporters.
+ */
+ private List m_exporters = new ArrayList();
+
+ /**
+ * List of managed services.
+ */
+ private List m_managedServices = new ArrayList();
+
+ /**
+ * List of component type.
+ */
+ private List m_types;
+
+ /**
+ * Handler description.
+ */
+ private ProvidedServiceHandlerDescription m_description;
+
+ /**
+ * Initialize the component type.
+ * @param desc : component type description to populate.
+ * @param metadata : component type metadata.
+ * @throws ConfigurationException : metadata are incorrect.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription desc, Element metadata) throws ConfigurationException {
+ Element[] provides = metadata.getElements("provides");
+ for (int i = 0; i < provides.length; i++) {
+ String action = provides[i].getAttribute("action");
+ if (action == null) {
+ throw new ConfigurationException("Invalid composition service providing : no specified action");
+ } else if (action.equalsIgnoreCase("implement")) {
+ String spec = provides[i].getAttribute("specification");
+ if (spec == null) {
+ throw new ConfigurationException("Malformed provides : the specification attribute is mandatory");
+ } else {
+ desc.addProvidedServiceSpecification(spec);
+ }
+ } else if (action.equalsIgnoreCase("export")) {
+ String spec = provides[i].getAttribute("specification");
+ if (spec == null) {
+ throw new ConfigurationException("Malformed exports - Missing the specification attribute");
+ } else {
+ desc.addProvidedServiceSpecification(spec);
+ }
+ } else {
+ throw new ConfigurationException("Invalid composition service providing : unknown action " + action);
+ }
+ }
+ }
+
+ /**
+ * Configure the handler.
+ * @param metadata : the metadata of the component
+ * @param configuration : the instance configuration
+ * @throws ConfigurationException : the exporter cannot be created
+ * @see CompositeHandler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ m_context = getCompositeManager().getContext();
+
+ Element[] provides = metadata.getElements("provides", "");
+ for (int i = 0; i < provides.length; i++) {
+ String action = provides[i].getAttribute("action");
+ if (action.equalsIgnoreCase("implement")) {
+ ProvidedService svc = new ProvidedService(this, provides[i], Integer.toString(i));
+ m_managedServices.add(svc);
+ } else if (action.equalsIgnoreCase("export")) {
+ boolean optional = false;
+ boolean aggregate = false;
+ String specification = provides[i].getAttribute("specification");
+
+ String filter = "(objectClass=" + specification + ")";
+
+ String opt = provides[i].getAttribute("optional");
+ optional = opt != null && opt.equalsIgnoreCase("true");
+
+ String agg = provides[i].getAttribute("aggregate");
+ aggregate = agg != null && agg.equalsIgnoreCase("true");
+
+ String givenFilter = provides[i].getAttribute("filter");
+ if (givenFilter != null) {
+ filter = "(&" + filter + givenFilter + ")"; //NOPMD
+ }
+
+ Filter fil = null;
+ try {
+ fil = m_context.createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("An exporter filter is invalid " + filter, e);
+ }
+
+ Comparator cmp = DependencyMetadataHelper.getComparator(provides[i], m_context);
+ int policy = DependencyMetadataHelper.getPolicy(provides[i]);
+ Class spec = DependencyMetadataHelper.loadSpecification(specification, m_context);
+
+ ServiceExporter imp = new ServiceExporter(spec, fil, aggregate, optional, cmp, policy, getCompositeManager().getServiceContext(), m_context, this, getCompositeManager());
+ m_exporters.add(imp);
+ } // Others case cannot happen. The test was already made during the factory initialization.
+ }
+
+ m_description = new ProvidedServiceHandlerDescription(this, m_managedServices, m_exporters);
+
+ }
+
+ /**
+ * Start method.
+ * Start all managed provided service.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#start()
+ */
+ public void start() {
+ // Compute imports and instances
+ computeAvailableServices();
+ computeAvailableTypes();
+
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService svc = (ProvidedService) m_managedServices.get(i);
+ try {
+ checkServiceSpecification(svc);
+ svc.start();
+ } catch (CompositionException e) {
+ error("Cannot start the provided service handler", e);
+ setValidity(false);
+ return;
+ }
+ }
+
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
+ exp.start();
+ }
+
+ isHandlerValid();
+ }
+
+ /**
+ * Stop method.
+ * Stop all managed provided service.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService svc = (ProvidedService) m_managedServices.get(i);
+ svc.stop();
+ }
+
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
+ exp.stop();
+ }
+ }
+
+ /**
+ * Check the handler validity.
+ * @see org.apache.felix.ipojo.composite.CompositeHandler#isValid()
+ */
+ private void isHandlerValid() {
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter exp = (ServiceExporter) m_exporters.get(i);
+ if (exp.getState() != DependencyModel.RESOLVED) {
+ setValidity(false);
+ return;
+ }
+ }
+
+ setValidity(true);
+ }
+
+ /**
+ * Handler state changed.
+ * @param state : the new instance state.
+ * @see CompositeHandler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ if (state == ComponentInstance.INVALID) {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService svc = (ProvidedService) m_managedServices.get(i);
+ svc.unregister();
+ }
+ return;
+ }
+
+ // If the new state is VALID => register all the services
+ if (state == ComponentInstance.VALID) {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService svc = (ProvidedService) m_managedServices.get(i);
+ svc.register();
+ }
+ return;
+ }
+ }
+
+ /**
+ * Notify the handler that an exporter becomes invalid.
+ *
+ * @param exporter : the implicated exporter.
+ */
+ public void invalidate(DependencyModel exporter) {
+ // An export is no more valid
+ if (getValidity()) {
+ setValidity(false);
+ }
+
+ }
+
+ /**
+ * Notify the handler that an exporter becomes valid.
+ *
+ * @param exporter : the implicated exporter.
+ */
+ public void validate(DependencyModel exporter) {
+ // An import becomes valid
+ if (!getValidity()) {
+ isHandlerValid();
+ }
+ }
+
+ /**
+ * Build the list of available specification.
+ * @return the list of available specification.
+ */
+ protected List getSpecifications() {
+ return m_services;
+ }
+
+ /**
+ * Build the list of available specifications.
+ */
+ private void computeAvailableServices() {
+ // Get instantiated services :
+ ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");
+
+ for (int i = 0; handler != null && i < handler.getInstances().size(); i++) {
+ SvcInstance svc = (SvcInstance) handler.getInstances().get(i);
+ String itf = svc.getServiceSpecification();
+ boolean agg = svc.isAggregate();
+ boolean opt = svc.isOptional();
+
+ SpecificationMetadata specMeta = new SpecificationMetadata(itf, m_context, agg, opt, this);
+ m_services.add(specMeta);
+ }
+
+ for (int i = 0; handler != null && i < handler.getRequirements().size(); i++) {
+ ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
+ String itf = imp.getSpecification().getName();
+ boolean agg = imp.isAggregate();
+ boolean opt = imp.isOptional();
+
+ SpecificationMetadata specMeta = new SpecificationMetadata(itf, m_context, agg, opt, this);
+ m_services.add(specMeta);
+ }
+ }
+
+ /**
+ * Check composite requirement against service specification requirement is available.
+ * @param svc : the provided service to check
+ * @throws CompositionException : occurs if the specification field of the service specification cannot be analyzed correctly.
+ */
+ private void checkServiceSpecification(ProvidedService svc) throws CompositionException {
+ try {
+ Class spec = m_context.getBundle().loadClass(svc.getSpecification());
+ Field specField = spec.getField("specification");
+ Object object = specField.get(null);
+ if (object instanceof String) {
+ Element specification = ManifestMetadataParser.parse((String) object);
+ Element[] reqs = specification.getElements("requires");
+ for (int j = 0; reqs != null && j < reqs.length; j++) {
+ ServiceImporter imp = getAttachedRequirement(reqs[j]);
+ if (imp != null) {
+ // Fix service-level dependency flag
+ imp.setServiceLevelDependency();
+ }
+ checkRequirement(imp, reqs[j]);
+ }
+ } else {
+ error("[" + getCompositeManager().getInstanceName() + "] The specification field of the service specification " + svc.getSpecification() + " needs to be a String");
+ throw new CompositionException("Service Specification checking failed : The specification field of the service specification " + svc.getSpecification() + " needs to be a String");
+ }
+ } catch (NoSuchFieldException e) {
+ return; // No specification field
+ } catch (ClassNotFoundException e) {
+ error("[" + getCompositeManager().getInstanceName() + "] The service specification " + svc.getSpecification() + " cannot be load");
+ throw new CompositionException("The service specification " + svc.getSpecification() + " cannot be loaded", e);
+ } catch (IllegalArgumentException e) {
+ error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
+ throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible", e);
+ } catch (IllegalAccessException e) {
+ error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible : " + e.getMessage());
+ throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " is not accessible", e);
+ } catch (ParseException e) {
+ error("[" + getCompositeManager().getInstanceName() + "] The field 'specification' of the service specification " + svc.getSpecification() + " does not contain a valid String : " + e.getMessage());
+ throw new CompositionException("The field 'specification' of the service specification " + svc.getSpecification() + " does not contain a valid String", e);
+ }
+ }
+
+ /**
+ * Look for the implementation (i.e. composite) requirement for the given service-level requirement metadata.
+ * @param element : the service-level requirement metadata
+ * @return the ServiceImporter object, null if not found or if the DependencyHandler is not plugged to the instance
+ */
+ private ServiceImporter getAttachedRequirement(Element element) {
+ ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");
+ if (handler == null) { return null; }
+
+ String identity = element.getAttribute("id");
+ if (identity != null) {
+ // Look for dependency Id
+ for (int i = 0; i < handler.getRequirements().size(); i++) {
+ ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
+ if (imp.getId().equals(identity)) { return imp; }
+ }
+ }
+
+ // If not found or no id, look for a dependency with the same specification
+ String requirement = element.getAttribute("specification");
+ for (int i = 0; i < handler.getRequirements().size(); i++) {
+ ServiceImporter imp = (ServiceImporter) handler.getRequirements().get(i);
+ if (imp.getId().equals(requirement) || imp.getSpecification().getName().equals(requirement)) { return imp; }
+ }
+ return null;
+ }
+
+ /**
+ * Check the correctness of the composite requirement against the service level dependency.
+ * @param imp : requirement to check
+ * @param elem : service-level dependency metadata
+ * @throws CompositionException : occurs if the requirement does not match with service-level specification requirement
+ */
+ private void checkRequirement(ServiceImporter imp, Element elem) throws CompositionException {
+ String optional = elem.getAttribute("optional");
+ boolean opt = optional != null && optional.equalsIgnoreCase("true");
+
+ String aggregate = elem.getAttribute("aggregate");
+ boolean agg = aggregate != null && aggregate.equalsIgnoreCase("true");
+
+ if (imp == null) {
+ // Add the missing requirement
+ ServiceDependencyHandler handler = (ServiceDependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":subservice");
+ if (handler == null) {
+ // Look for the ServiceDependencyHandler factory
+ HandlerManager handlerManager = null;
+ try {
+ ServiceReference[] refs = m_context.getServiceReferences(Factory.class.getName(), "(&(handler.name=subservice)(handler.namespace=" + HandlerFactory.IPOJO_NAMESPACE + ")(handler.type=composite))");
+ Factory factory = (Factory) m_context.getService(refs[0]);
+ handlerManager = (HandlerManager) factory.createComponentInstance(null, getCompositeManager().getServiceContext());
+ } catch (InvalidSyntaxException e) {
+ // Should not happen
+ } catch (UnacceptableConfiguration e) {
+ // Should not happen
+ } catch (MissingHandlerException e) {
+ // Should not happen
+ } catch (ConfigurationException e) {
+ // Should not happen
+ }
+
+ // Add the required handler
+ try {
+ handlerManager.init(getCompositeManager(), new Element("composite", ""), new Properties());
+ } catch (ConfigurationException e) {
+ error("Internal error : cannot configure the Import Handler : " + e.getMessage());
+ throw new CompositionException("Internal error : cannot configure the Import Handler", e);
+ }
+ handler = (ServiceDependencyHandler) handlerManager.getHandler();
+ getCompositeManager().addCompositeHandler(handlerManager);
+ }
+
+ String spec = elem.getAttribute("specification");
+ String filter = "(&(objectClass=" + spec + ")(!(instance.name=" + getCompositeManager().getInstanceName() + ")))"; // Cannot import yourself
+ String givenFilter = elem.getAttribute("filter");
+ if (givenFilter != null) {
+ filter = "(&" + filter + givenFilter + ")"; //NOPMD
+ }
+
+ BundleContext context = new PolicyServiceContext(getCompositeManager().getGlobalContext(), getCompositeManager().getParentServiceContext(), PolicyServiceContext.GLOBAL);
+
+ Filter fil = null;
+ try {
+ fil = getCompositeManager().getGlobalContext().createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new CompositionException("A required filter " + filter + " is malformed", e);
+ }
+
+ Class specToImport = null;
+ try {
+ specToImport = getCompositeManager().getGlobalContext().getBundle().loadClass(spec);
+ } catch (ClassNotFoundException e) {
+ throw new CompositionException("A required specification cannot be loaded : " + spec, e);
+ }
+
+ ServiceImporter importer = new ServiceImporter(specToImport, fil, agg, opt, null, DependencyModel.DYNAMIC_BINDING_POLICY, context, null, handler);
+
+ handler.getRequirements().add(importer);
+ SpecificationMetadata specMeta = new SpecificationMetadata(spec, m_context, agg, opt, this);
+ m_services.add(specMeta); // Update the available types
+ return;
+ }
+
+ if (imp.isAggregate() && !agg) {
+ error("[" + getCompositeManager().getInstanceName() + "] The requirement " + elem.getAttribute("specification") + " is aggregate in the implementation and is declared as a simple service-level requirement");
+ throw new CompositionException("The requirement " + elem.getAttribute("specification") + " is aggregate in the implementation and is declared as a simple service-level requirement");
+ }
+
+ String filter = elem.getAttribute("filter");
+ if (filter != null) {
+ String filter2 = imp.getFilter();
+ if (filter2 == null || !filter2.equalsIgnoreCase(filter)) {
+ error("[" + getCompositeManager().getInstanceName() + "] The specification requirement " + elem.getAttribute("specification") + " as not the same filter as declared in the service-level requirement");
+ throw new CompositionException("The specification requirement " + elem.getAttribute("specification") + " as not the same filter as declared in the service-level requirement");
+ }
+ }
+ }
+
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Build available instance types.
+ */
+ private void computeAvailableTypes() {
+ InstanceHandler handler = (InstanceHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":instance");
+ if (handler == null) {
+ m_types = new ArrayList();
+ } else {
+ m_types = handler.getUsedType();
+ }
+ }
+
+ public List getInstanceType() {
+ return m_types;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java
new file mode 100644
index 0000000..5c22246
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java
@@ -0,0 +1,96 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.composite.CompositeHandler;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+
+/**
+ * Provided Service Handler Description for composite.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandlerDescription extends HandlerDescription {
+
+ /**
+ * Provided Service Description list.
+ */
+ private List m_services = new ArrayList();
+
+ /**
+ * List of exports.
+ */
+ private List m_exports;
+
+ /**
+ * Constructor.
+ *
+ * @param handler : composite handler.
+ * @param services : The list of Provided Service.
+ * @param exporters : list of managed exports
+ */
+ public ProvidedServiceHandlerDescription(CompositeHandler handler, List services, List exporters) {
+ super(handler);
+ m_services = services;
+ m_exports = exporters;
+ }
+
+ /**
+ * Get the handler description.
+ * @return the provided service handler description
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element services = super.getHandlerInfo();
+ for (int i = 0; i < m_services.size(); i++) {
+ ProvidedService svc = (ProvidedService) m_services.get(i);
+ Element service = new Element("service", "");
+ String state = "unregistered";
+ if (svc.isRegistered()) {
+ state = "registered";
+ }
+ String spec = "[" + svc.getSpecification() + "]";
+ service.addAttribute(new Attribute("Specification", spec));
+ service.addAttribute(new Attribute("State", state));
+ services.addElement(service);
+ }
+
+ for (int i = 0; i < m_exports.size(); i++) {
+ ServiceExporter exp = (ServiceExporter) m_exports.get(i);
+ Element expo = new Element("Exports", "");
+ expo.addAttribute(new Attribute("Specification", exp.getSpecification().getName()));
+ expo.addAttribute(new Attribute("Filter", exp.getFilter()));
+ if (exp.getState() == DependencyModel.RESOLVED) {
+ expo.addAttribute(new Attribute("State", "resolved"));
+ } else {
+ expo.addAttribute(new Attribute("State", "unresolved"));
+ }
+ services.addElement(expo);
+ }
+
+ return services;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
new file mode 100644
index 0000000..bb0b14f
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
@@ -0,0 +1,176 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.apache.felix.ipojo.util.SecurityHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Export an service from the scope to the parent context.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceExporter extends DependencyModel {
+
+ /**
+ * Destination context.
+ */
+ private BundleContext m_destination;
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Map of service reference - service registration storing exported services.
+ */
+ private Map/*<ServiceReference, ServiceRegistration>*/m_registrations = new HashMap();
+
+ /**
+ * Constructor.
+ *
+ * @param specification : exported service specification.
+ * @param filter : LDAP filter
+ * @param multiple : is the export an aggregate export?
+ * @param optional : is the export optional?
+ * @param cmp : comparator to use in the dependency
+ * @param policy : binding policy.
+ * @param from : internal service context
+ * @param dest : parent bundle context
+ * @param listener : dependency lifecycle listener to notify when the dependency state change.
+ * @param manager : composite manager
+ */
+ public ServiceExporter(Class specification, Filter filter, boolean multiple, boolean optional, Comparator cmp, int policy, ServiceContext from, BundleContext dest, DependencyStateListener listener, CompositeManager manager) {
+ super(specification, multiple, optional, filter, cmp, policy, from, listener, manager);
+
+ m_destination = dest;
+
+ m_manager = manager;
+
+ }
+
+ /**
+ * Transform service reference property in a dictionary.
+ * instance.name and factory.name are injected too.
+ * @param ref : the service reference.
+ * @return the dictionary containing all property of the given service reference.
+ */
+ private Dictionary getProps(ServiceReference ref) {
+ Properties prop = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ prop.put(keys[i], ref.getProperty(keys[i]));
+ }
+
+ prop.put("instance.name", m_manager.getInstanceName());
+ prop.put("factory.name", m_manager.getFactory().getName());
+
+ return prop;
+ }
+
+ /**
+ * Stop an exporter.
+ * Remove the service listener
+ * Unregister all exported services.
+ */
+ public void stop() {
+ super.stop();
+ Set refs = m_registrations.keySet();
+ Iterator iterator = refs.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference ref = (ServiceReference) iterator.next();
+ ServiceRegistration reg = (ServiceRegistration) m_registrations.get(ref);
+ try {
+ reg.unregister();
+ } catch (IllegalStateException e) {
+ // The service is already unregistered
+ // Do nothing silently
+ }
+ }
+ m_registrations.clear();
+ }
+
+ /**
+ * A service has been injected. Register it.
+ * @param reference : the new reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceArrival(ServiceReference reference) {
+ Object svc = getService(reference);
+ // Security Check
+ if (SecurityHelper.hasPermissionToRegisterService(getSpecification().getName(), m_destination)) {
+ ServiceRegistration reg = m_destination
+ .registerService(getSpecification().getName(), svc, getProps(reference));
+ m_registrations.put(reference, reg);
+ } else {
+ throw new SecurityException("The bundle " + m_destination.getBundle().getBundleId() + " does not have the "
+ + "permission to register the service " + getSpecification().getName());
+ }
+ }
+
+ /**
+ * An exported service was modified.
+ * @param reference : modified reference
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void onServiceModification(ServiceReference reference) {
+ ServiceRegistration reg = (ServiceRegistration) m_registrations.get(reference);
+ if (reg != null) {
+ reg.setProperties(getProps(reference));
+ }
+ }
+
+ /**
+ * An exported service disappears.
+ * @param reference : service reference
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void onServiceDeparture(ServiceReference reference) {
+ ServiceRegistration reg = (ServiceRegistration) m_registrations.get(reference);
+ if (reg != null) {
+ reg.unregister();
+ }
+ m_registrations.remove(reference);
+ }
+
+ /**
+ * On Dependency Reconfiguration notification method.
+ * @param departs : leaving service references.
+ * @param arrivals : new injected service references.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[])
+ */
+ public void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals) {
+ throw new UnsupportedOperationException("Dynamic dependency reconfiguration is not supported by service exporter");
+ }
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.java
new file mode 100644
index 0000000..392de87
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.java
@@ -0,0 +1,158 @@
+/*
+ * 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.composite.service.provides;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Represent a service specification.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SpecificationMetadata {
+
+ /**
+ * Name of the specification, i.e. name of the interface.
+ */
+ private String m_name;
+
+ /**
+ * List of the method contained in the specification.
+ */
+ private List/* <MethodMetadata> */m_methods = new ArrayList/* <MethodMetadata> */();
+
+ /**
+ * Is the specification an aggregate?
+ */
+ private boolean m_isAggregate;
+
+ /**
+ * Is the specification optional?
+ */
+ private boolean m_isOptional = false;
+
+ /**
+ * Is the specification an interface?
+ */
+ private boolean m_isInterface = true;
+
+ /**
+ * Component Type.
+ */
+ private String m_componentType = null;
+
+ /**
+ * Reference on the handler.
+ */
+ private ProvidedServiceHandler m_handler;
+
+ /**
+ * Constructor.
+ * @param name : specification name.
+ * @param context : bundle context.
+ * @param isAggregate : is the specification aggregate.
+ * @param isOptional : is the specification optional.
+ * @param psd : the handler.
+ */
+ public SpecificationMetadata(String name, BundleContext context, boolean isAggregate, boolean isOptional, ProvidedServiceHandler psd) {
+ m_name = name;
+ m_handler = psd;
+
+ // Populate methods :
+ try {
+ Class clazz = context.getBundle().loadClass(name);
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ MethodMetadata method = new MethodMetadata(methods[i]);
+ m_methods.add(method);
+ }
+ } catch (ClassNotFoundException e) {
+ m_handler.error("Cannot open " + name + " : " + e.getMessage());
+ return;
+ }
+
+ m_isAggregate = isAggregate;
+ m_isOptional = isOptional;
+ }
+
+ /**
+ * Constructor.
+ * @param clazz : class
+ * @param type : component type
+ * @param psd : the parent handler
+ */
+ public SpecificationMetadata(Class clazz, String type, ProvidedServiceHandler psd) {
+ m_handler = psd;
+ m_isAggregate = false;
+ m_isOptional = false;
+ m_componentType = type;
+ m_name = clazz.getName();
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ MethodMetadata method = new MethodMetadata(methods[i]);
+ m_methods.add(method);
+ }
+ m_isInterface = false;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public List/* <MethodMetadata> */getMethods() {
+ return m_methods;
+ }
+
+ /**
+ * Get a method by its name.
+ * @param name : method name
+ * @return the method metadata contained in the current specification with the given name. Null if the method is not found.
+ */
+ public MethodMetadata getMethodByName(String name) {
+ for (int i = 0; i < m_methods.size(); i++) {
+ MethodMetadata met = (MethodMetadata) m_methods.get(i);
+ if (met.getMethod().getName().equals(name)) { return met; }
+ }
+ return null;
+ }
+
+ public boolean isAggregate() {
+ return m_isAggregate;
+ }
+
+ public boolean isOptional() {
+ return m_isOptional;
+ }
+
+ public boolean isInterface() {
+ return m_isInterface;
+ }
+
+ public void setIsOptional(boolean optional) {
+ m_isOptional = optional;
+ }
+
+ public String getComponentType() {
+ return m_componentType;
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/util/SourceManager.java b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/util/SourceManager.java
new file mode 100644
index 0000000..b04b2df
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/java/org/apache/felix/ipojo/composite/util/SourceManager.java
@@ -0,0 +1,376 @@
+/*
+ * 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.composite.util;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.Tracker;
+import org.apache.felix.ipojo.util.TrackerCustomizer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This class manages context-source management.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SourceManager implements ContextListener {
+
+ /**
+ * Source Name service property.
+ */
+ public static final String SOURCE_NAME = "source.name";
+
+ /**
+ * Managed dependency.
+ */
+ private DependencyModel m_dependency;
+
+ /**
+ * List of monitored context sources.
+ */
+ private List/* <ContextSource> */m_sources = new ArrayList(1);
+
+ /**
+ * PRoperties contained in the original filter.
+ */
+ private String[] m_properties;
+
+ /**
+ * Original filter (containing variables).
+ */
+ private String m_filter;
+
+ /**
+ * Bundle context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Service Tracker List.
+ */
+ private List/*<SourceTracker>*/m_trackers = new ArrayList(1);
+
+ /**
+ * Constructor.
+ * @param sources : context-source attribute from the dependency metadata
+ * @param depfilter : original dependency filter
+ * @param dependency : dependency object
+ * @param manager : composite manager
+ * @throws ConfigurationException : the sources are incorrect.
+ */
+ public SourceManager(String sources, String depfilter, DependencyModel dependency, CompositeManager manager) throws ConfigurationException {
+ m_filter = depfilter;
+ m_properties = getProperties(depfilter);
+ m_dependency = dependency;
+ m_context = manager.getGlobalContext();
+ if (manager.getParentServiceContext() == null) {
+ // The parent is the global context
+ parseSources(sources, manager.getGlobalContext(), manager.getGlobalContext(), manager.getServiceContext());
+ } else {
+ parseSources(sources, manager.getGlobalContext(), manager.getParentServiceContext(), manager.getServiceContext());
+ }
+ }
+
+ /**
+ * Start the context management.
+ */
+ public void start() {
+ for (int i = 0; i < m_trackers.size(); i++) {
+ ((SourceTracker) m_trackers.get(i)).open();
+ }
+ computeFilter();
+ }
+
+ /**
+ * Stop the context management.
+ */
+ public void stop() {
+ for (int i = 0; i < m_trackers.size(); i++) {
+ ((SourceTracker) m_trackers.get(i)).close();
+ }
+ setFilter(m_filter);
+ m_sources.clear();
+ }
+
+ /**
+ * Get the state of this source manager.
+ * @return the state of this source manager.
+ */
+ public int getState() {
+ if (m_sources.isEmpty()) {
+ return DependencyModel.UNRESOLVED;
+ } else {
+ return DependencyModel.RESOLVED;
+ }
+ }
+
+ /**
+ * Set the filter of the managed dependency.
+ * @param filter : the new filter to apply
+ */
+ private void setFilter(String filter) {
+ if (!filter.equals(m_dependency.getFilter())) {
+ // Reconfigure
+ try {
+ m_dependency.setFilter(m_context.createFilter(filter));
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException("A context filter is invalid : " + filter, e);
+ }
+ }
+ }
+
+ /**
+ * Compute the new filter.
+ */
+ private void computeFilter() {
+ String fil = m_filter;
+ synchronized (this) {
+ for (int i = 0; i < m_sources.size(); i++) {
+ Dictionary props = ((ContextSource) m_sources.get(i)).getContext();
+ fil = substitute(fil, props); //NOPMD
+ }
+ }
+ if (!fil.equals(m_dependency.getFilter())) {
+ setFilter(fil);
+ }
+ }
+
+ /**
+ * This method substitute ${var} substring by values stored in a map.
+ * @param str : string with variables
+ * @param values : dictionary containing the variable name and the value.
+ * @return resulted string
+ */
+ public static String substitute(String str, Dictionary values) {
+ int len = str.length();
+ StringBuffer buffer = new StringBuffer(len);
+
+ int prev = 0;
+ int start = str.indexOf("${");
+ int end = str.indexOf('}', start);
+ while (start != -1 && end != -1) {
+ String key = str.substring(start + 2, end);
+ Object value = values.get(key);
+ if (value == null) {
+ buffer.append(str.substring(prev, end + 1));
+ } else {
+ buffer.append(str.substring(prev, start));
+ buffer.append(value);
+ }
+ prev = end + 1;
+ if (prev >= str.length()) {
+ break;
+ }
+
+ start = str.indexOf("${", prev);
+ if (start != -1) {
+ end = str.indexOf('}', start);
+ }
+ }
+
+ buffer.append(str.substring(prev));
+
+ return buffer.toString();
+ }
+
+ /**
+ * Compute the properties (${name}) from the given filter.
+ * @param str : string form of the filter.
+ * @return the list of found properties.
+ */
+ public static String[] getProperties(String str) {
+ List list = new ArrayList();
+ int prev = 0;
+ int start = str.indexOf("${");
+ int end = str.indexOf('}', start);
+ while (start != -1 && end != -1) {
+ String key = str.substring(start + 2, end);
+ list.add(key);
+ prev = end + 1;
+ if (prev >= str.length()) {
+ break;
+ }
+
+ start = str.indexOf("${", prev);
+ if (start != -1) {
+ end = str.indexOf('}', start);
+ }
+ }
+
+ return (String[]) list.toArray(new String[list.size()]);
+ }
+
+ /**
+ * A context source has modified a monitored property.
+ * @param source : source
+ * @param property : modified property
+ * @param value : new value.
+ * @see org.apache.felix.ipojo.ContextListener#update(org.apache.felix.ipojo.ContextSource, java.lang.String, java.lang.Object)
+ */
+ public synchronized void update(ContextSource source, String property, Object value) {
+ computeFilter();
+ }
+
+ /**
+ * Parse the context-source attribute in order to create source tracker object.
+ * @param sourceAtt : context-source attribute.
+ * @param global : global bundle context.
+ * @param parent : parent bundle context.
+ * @param local : local bundle context.
+ * @throws ConfigurationException : the context-source attribute is invalid.
+ */
+ private void parseSources(String sourceAtt, BundleContext global, BundleContext parent, BundleContext local) throws ConfigurationException {
+ String[] sources = ParseUtils.split(sourceAtt, ",");
+ for (int i = 0; i < sources.length; i++) {
+ String[] srcs = ParseUtils.split(sources[i], ":");
+ if (srcs.length == 1) {
+ // No prefix use local. //TODO choose default case.
+ SourceTracker tracker = new SourceTracker(srcs[0], local);
+ m_trackers.add(tracker);
+ } else if (srcs.length == 2) {
+ // According to prefix add the source in the good list.
+ if (srcs[0].equalsIgnoreCase("parent")) {
+ SourceTracker tracker = new SourceTracker(srcs[1], parent);
+ m_trackers.add(tracker);
+ } else if (srcs[0].equalsIgnoreCase("local")) {
+ SourceTracker tracker = new SourceTracker(srcs[1], local);
+ m_trackers.add(tracker);
+ } else if (srcs[0].equalsIgnoreCase("global")) {
+ SourceTracker tracker = new SourceTracker(srcs[1], global);
+ m_trackers.add(tracker);
+ } else {
+ throw new ConfigurationException("Unknowns context scope : " + srcs[0]);
+ }
+ } else {
+ throw new ConfigurationException("Malformed context source : " + sources[i]);
+ }
+ }
+ }
+
+ /**
+ * A context source appears.
+ * @param source : new context source.
+ */
+ private void addContextSource(ContextSource source) {
+ m_sources.add(source);
+ computeFilter();
+ source.registerContextListener(this, m_properties);
+ }
+
+ /**
+ * A context source disappears.
+ * @param source : leaving context source.
+ */
+ private void removeContextSource(ContextSource source) {
+ m_sources.remove(source);
+ computeFilter();
+ }
+
+ private class SourceTracker implements TrackerCustomizer {
+
+ /**
+ * Service tracker.
+ */
+ private Tracker m_tracker;
+
+ /**
+ * Constructor.
+ * @param name : name of the required context-source.
+ * @param countext : bundle context to use.
+ * @throws ConfigurationException : the context-source name is invalid.
+ */
+ public SourceTracker(String name, BundleContext countext) throws ConfigurationException {
+ String fil = "(&(" + Constants.OBJECTCLASS + "=" + ContextSource.class.getName() + ")(" + SOURCE_NAME + "=" + name + "))";
+ try {
+ Filter filter = countext.createFilter(fil);
+ m_tracker = new Tracker(countext, filter, this);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("A Context source filter is invalid " + fil, e);
+ }
+ }
+
+ /**
+ * Open the tracker.
+ */
+ public void open() {
+ m_tracker.open();
+ }
+
+ /**
+ * Close the tracker.
+ */
+ public void close() {
+ m_tracker.close();
+ }
+
+ /**
+ * A new context-source was added.
+ * This method inject the context-source object in the source manager.
+ * @param reference : service reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void addedService(ServiceReference reference) {
+ addContextSource((ContextSource) m_tracker.getService(reference));
+ }
+
+ /**
+ * A new context-source is adding in the tracker..
+ * @param reference : service reference
+ * @return true.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+ */
+ public boolean addingService(ServiceReference reference) {
+ return true;
+ }
+
+ /**
+ * A used context-source is modified.
+ * @param reference : service reference.
+ * @param service : service object.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Nothing to do.
+ }
+
+ /**
+ * A used context-source disappears.
+ * This method notify the Source Manager in order to manage this departure.
+ * @param reference : service reference.
+ * @param service : service object.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ removeContextSource((ContextSource) service);
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/composite/src/main/resources/composite.xsd b/ipojo/runtime/composite/src/main/resources/composite.xsd
new file mode 100644
index 0000000..2d01df1
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/resources/composite.xsd
@@ -0,0 +1,147 @@
+<!--
+ 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.
+-->
+<xs:schema elementFormDefault="qualified"
+ targetNamespace="org.apache.felix.ipojo.composite"
+ xmlns="org.apache.felix.ipojo.composite"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ipojo="org.apache.felix.ipojo">
+
+ <xs:import namespace="org.apache.felix.ipojo" schemaLocation="http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"></xs:import>
+ <xs:complexType name="CompositeType">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="subservice" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0"
+ maxOccurs="unbounded">
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded">
+ </xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional"></xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean"
+ use="optional">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="subservice" type="SubserviceType" />
+ <xs:element name="provides" type="CompositeProvidesType" />
+
+ <xs:complexType name="CompositeProvidesType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+ <xs:sequence>
+ <xs:element name="delegation" type="DelegationType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+
+ <xs:attribute name="action">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="implement"></xs:enumeration>
+ <xs:enumeration value="export"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="SubserviceType">
+ <xs:complexContent>
+ <xs:extension base="ipojo:ServiceDependencyType">
+
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="action" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="import"></xs:enumeration>
+ <xs:enumeration value="instantiate"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="specification" type="xs:string"
+ use="required">
+ </xs:attribute>
+ <xs:attribute name="context-source" type="xs:string"
+ use="optional">
+ </xs:attribute>
+ <xs:attribute name="scope">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"></xs:enumeration>
+ <xs:enumeration value="composite"></xs:enumeration>
+ <xs:enumeration value="composite+global"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:simpleType name="actionType">
+ <xs:restriction base="xs:string"></xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="CompositePropertyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType" minOccurs="0" maxOccurs="unbounded"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional"></xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="CompositeInstanceType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="CompositePropertyType"></xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+ <xs:attribute name="component" type="xs:string"
+ use="required">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="instance" type="CompositeInstanceType"></xs:element>
+
+ <xs:element name="composite" type="CompositeType"></xs:element>
+
+ <xs:complexType name="DelegationType">
+ <xs:attribute name="method" type="xs:string" use="required"></xs:attribute>
+ <xs:attribute name="policy" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="all"></xs:enumeration>
+ <xs:enumeration value="one"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/runtime/composite/src/main/resources/metadata.xml b/ipojo/runtime/composite/src/main/resources/metadata.xml
new file mode 100644
index 0000000..13b2163
--- /dev/null
+++ b/ipojo/runtime/composite/src/main/resources/metadata.xml
@@ -0,0 +1,43 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <!-- Composite Handler -->
+ <handler
+ classname="org.apache.felix.ipojo.composite.instance.InstanceHandler"
+ name="instance" type="composite" architecture="false" level="1">
+ <requires filter="(factory.state=1)" field="m_factories"
+ optional="true">
+ <callback type="bind" method="bindFactory" />
+ <callback type="unbind" method="unbindFactory" />
+ </requires>
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.composite.service.instantiator.ServiceDependencyHandler"
+ name="subservice" type="composite" architecture="false">
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.composite.service.provides.ProvidedServiceHandler"
+ name="provides" type="composite" architecture="false" level="3">
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.composite.architecture.ArchitectureHandler"
+ name="architecture" type="composite" architecture="false">
+ <!-- the architecture service is published by the handler manually -->
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-api-test/pom.xml b/ipojo/runtime/core-it/ipojo-api-test/pom.xml
new file mode 100644
index 0000000..a29cc85
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-api-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.composite</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.api</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.whiteboard</artifactId>
+ <version>1.4.0</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/FooImpl.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/FooImpl.java
new file mode 100644
index 0000000..8e396d6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/FooImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.api.components;
+
+import org.apache.felix.ipojo.runtime.core.api.services.Foo;
+
+public class FooImpl implements Foo {
+
+ // private List<String> m_list = new ArrayList<String>();
+
+ public void doSomething() {
+ // Do something...
+ System.out.println("Hello World !");
+ }
+
+ public FooImpl(String s) {
+ _setIM(s);
+ }
+
+ public void _setIM(String s) {
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/HostImpl.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/HostImpl.java
new file mode 100644
index 0000000..ab75f87
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/HostImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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.api.components;
+
+import org.osgi.framework.ServiceReference;
+
+public class HostImpl {
+
+ public void arrival(ServiceReference ref) {
+
+ }
+
+ public void departure(ServiceReference ref) {
+
+ }
+
+ public void modification(ServiceReference ref) {
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyComponentImpl.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyComponentImpl.java
new file mode 100644
index 0000000..a07feb8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyComponentImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.api.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.runtime.core.api.services.Foo;
+
+/**
+ * This class is marked as a component to be manipulated.
+ */
+@Component(name="do-not-use-this-factory", public_factory = false)
+public class MyComponentImpl {
+
+ private Foo myFoo;
+
+ private int anInt;
+
+ public MyComponentImpl() {
+ anInt = 2;
+ }
+
+ public MyComponentImpl(int i) {
+ anInt = i;
+ }
+
+ public void start() {
+ myFoo.doSomething();
+ if (anInt > 0) {
+ System.out.println("Set int to " + anInt);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyServiceImpl.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyServiceImpl.java
new file mode 100644
index 0000000..7973ed7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/MyServiceImpl.java
@@ -0,0 +1,28 @@
+/*
+ * 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.api.components;
+
+import org.apache.felix.ipojo.runtime.core.api.services.MyService;
+
+public class MyServiceImpl implements MyService {
+ public double compute(double value) {
+ return Math.exp(value * Math.cosh(value));
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/PlainHelloImpl.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/PlainHelloImpl.java
new file mode 100755
index 0000000..79f29bc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/components/PlainHelloImpl.java
@@ -0,0 +1,46 @@
+/*
+* 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.api.components;
+
+import org.apache.felix.ipojo.runtime.core.api.services.PlainHello;
+
+
+public class PlainHelloImpl implements PlainHello {
+
+ public void sayHello() {
+ System.out.println("Plainly Hello :D");
+
+ }
+
+ public PlainHelloImpl() {
+ System.out.println("in constructor");
+ }
+
+
+ public void start() {
+
+ System.out.println("Hello, this is the plain hello component start method");
+ }
+
+ public void stop() {
+ System.out.println("Bye, this is the plain hello component stop method");
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/BarService.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/BarService.java
new file mode 100644
index 0000000..faa9f38
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/BarService.java
@@ -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.felix.ipojo.runtime.core.api.services;
+
+public interface BarService {
+
+ public void doSomethingWithBar();
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/Foo.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/Foo.java
new file mode 100644
index 0000000..719b2fd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/Foo.java
@@ -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.felix.ipojo.runtime.core.api.services;
+
+public interface Foo {
+
+
+ public void doSomething();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/MyService.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/MyService.java
new file mode 100644
index 0000000..ed24f45
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/MyService.java
@@ -0,0 +1,24 @@
+/*
+ * 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.api.services;
+
+public interface MyService {
+ double compute(double value);
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/PlainHello.java b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/PlainHello.java
new file mode 100755
index 0000000..1f07468
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/main/java/org/apache/felix/ipojo/runtime/core/api/services/PlainHello.java
@@ -0,0 +1,24 @@
+/*
+* 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.api.services;
+
+public interface PlainHello {
+ public void sayHello();
+
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Common.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Common.java
new file mode 100644
index 0000000..df7c115
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Common.java
@@ -0,0 +1,73 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.composite.CompositeManager;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+@ExamReactorStrategy(PerMethod.class)
+public class Common extends BaseTest {
+
+ public static ServiceContext getServiceContext(ComponentInstance ci) {
+ if (ci instanceof CompositeManager) {
+ return ((CompositeManager) ci).getServiceContext();
+ } else {
+ throw new RuntimeException("Cannot get the service context from a non composite instance");
+ }
+ }
+
+ @Override
+ public boolean deployiPOJOComposite() {
+ return true;
+ }
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.whiteboard").versionAsInProject(),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.api").versionAsInProject()
+ };
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.api.components"
+ );
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/CompositeTest.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/CompositeTest.java
new file mode 100644
index 0000000..6fa187a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/CompositeTest.java
@@ -0,0 +1,247 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.api.Dependency;
+import org.apache.felix.ipojo.api.PrimitiveComponentType;
+import org.apache.felix.ipojo.api.Service;
+import org.apache.felix.ipojo.api.composite.*;
+import org.apache.felix.ipojo.runtime.core.api.components.FooImpl;
+import org.apache.felix.ipojo.runtime.core.api.components.MyComponentImpl;
+import org.apache.felix.ipojo.runtime.core.api.services.Foo;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
+
+public class CompositeTest extends Common {
+
+ private BundleContext context;
+
+ @Before
+ public void setUp() {
+ context = getContext();
+ }
+
+ @Test
+ public void createACompositeWithcontainedInstance() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ PrimitiveComponentType cons = createAConsumer();
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("comp1")
+ .addInstance(new Instance(prov.getFactory().getName()))
+ .addInstance(new Instance(cons.getFactory().getName()));
+
+ ComponentInstance ci = type.createInstance();
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+
+ // Stop cons
+ cons.stop();
+ assertThat("ci is invalid", ci.getState(), is(ComponentInstance.INVALID));
+
+ // Restart cons
+ cons.start();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createACompositeWithAnInstantiatedService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ prov.start();
+ PrimitiveComponentType cons = createAConsumer();
+
+ ServiceReference[] refs = osgiHelper.getServiceReferences(Factory.class.getName(),
+ "(component.providedServiceSpecifications=" + Foo.class.getName() + ")");
+ assertThat(refs.length, is(not(0)));
+
+ Factory factory = (Factory) osgiHelper.getRawServiceObject(refs[0]);
+ System.out.println(factory.getComponentDescription().getDescription());
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("comp2")
+ .addSubService(new InstantiatedService().setSpecification(Foo.class.getName()))
+ .addInstance(new Instance(cons.getFactory().getName()));
+
+ ComponentInstance ci = type.createInstance();
+
+ System.out.println(ci.getInstanceDescription().getDescription());
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+
+ // Stop prov
+ prov.stop();
+ assertThat("ci is invalid", ci.getState(), is(ComponentInstance.INVALID));
+
+ // Restart prov
+ prov.start();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createACompositeWithAnOptionalInstantiatedService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ prov.start();
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("comp3")
+ .addSubService(new InstantiatedService().setSpecification(Foo.class.getName()).setOptional(true));
+
+ ComponentInstance ci = type.createInstance();
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+
+ // Stop prov
+ prov.stop();
+ assertThat("ci is valid - 1", ci.getState(), is(ComponentInstance.VALID));
+
+ // Restart prov
+ prov.start();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createACompositeWithAnImportedService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ prov.createInstance();
+ PrimitiveComponentType cons = createAConsumer();
+
+ ServiceReference[] refs = osgiHelper.getServiceReferences(Factory.class.getName(),
+ "(component.providedServiceSpecifications=" + Foo.class.getName() + ")");
+ assertThat(refs.length, is(not(0)));
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("comp2")
+ .addSubService(new ImportedService().setSpecification(Foo.class.getName()))
+ .addInstance(new Instance(cons.getFactory().getName()));
+
+ ComponentInstance ci = type.createInstance();
+
+ System.out.println(ci.getInstanceDescription().getDescription());
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+
+ // Stop prov
+ prov.stop();
+ assertThat("ci is invalid", ci.getState(), is(ComponentInstance.INVALID));
+
+ // Restart prov
+ prov.start();
+ prov.createInstance();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createACompositeWithAnOptionalImportedService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ prov.createInstance();
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("comp3")
+ .addSubService(new ImportedService().setSpecification(Foo.class.getName()).setOptional(true));
+
+ ComponentInstance ci = type.createInstance();
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+
+ // Stop prov
+ prov.stop();
+ assertThat("ci is valid - 1", ci.getState(), is(ComponentInstance.VALID));
+
+ // Restart prov
+ prov.start();
+ prov.createInstance();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createACompositeWithExportingAService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Define the component types
+ PrimitiveComponentType prov = createAProvider();
+ prov.start();
+ PrimitiveComponentType cons = createAConsumer();
+ ComponentInstance c = cons.createInstance();
+
+ CompositeComponentType type = new CompositeComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("compExport")
+ .addSubService(new InstantiatedService().setSpecification(Foo.class.getName()))
+ .addService(new ExportedService().setSpecification(Foo.class.getName()));
+
+ ComponentInstance ci = type.createInstance();
+
+ assertThat("ci is valid", ci.getState(), is(ComponentInstance.VALID));
+ assertThat("c is valid", c.getState(), is(ComponentInstance.VALID));
+
+
+ // Stop prov
+ prov.stop();
+ assertThat("ci is invalid", ci.getState(), is(ComponentInstance.INVALID));
+ assertThat("c is invalid", c.getState(), is(ComponentInstance.INVALID));
+
+
+ // Restart prov
+ prov.start();
+ assertThat("ci is valid - 2", ci.getState(), is(ComponentInstance.VALID));
+ assertThat("c is valid - 2", c.getState(), is(ComponentInstance.VALID));
+
+
+ }
+
+ private PrimitiveComponentType createAProvider() {
+ return new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(FooImpl.class.getName())
+ .setPublic(true)
+ .addService(new Service()); // Provide the FooService
+ }
+
+ private PrimitiveComponentType createAConsumer() {
+ return new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(MyComponentImpl.class.getName())
+ .addDependency(new Dependency().setField("myFoo"))
+ .setValidateMethod("start");
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/ExternalHandlerTest.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/ExternalHandlerTest.java
new file mode 100644
index 0000000..e478c79
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/ExternalHandlerTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.api.PrimitiveComponentType;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.runtime.core.api.components.HostImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+
+public class ExternalHandlerTest extends Common {
+
+
+ private BundleContext context;
+
+ @Before
+ public void setUp() {
+ context = getContext();
+ }
+
+ @Test
+ public void createAHost() throws Exception {
+ PrimitiveComponentType type = createAWhiteboardHost();
+ ComponentInstance ci = type.createInstance();
+ assertThat(ci.getState(), is(ComponentInstance.VALID));
+ HandlerDescription hd = ci.getInstanceDescription().getHandlerDescription(Whiteboard.NAMESPACE + ":" + Whiteboard.NAME);
+ assertThat(hd, is(notNullValue()));
+ }
+
+ @Test
+ public void createDoubleHost() throws Exception {
+ PrimitiveComponentType type = createASecondWhiteboardHost();
+ ComponentInstance ci = type.createInstance();
+ assertThat(ci.getState(), is(ComponentInstance.VALID));
+ HandlerDescription hd = ci.getInstanceDescription().getHandlerDescription(Whiteboard.NAMESPACE + ":" + Whiteboard.NAME);
+ assertThat(hd, is(notNullValue()));
+ }
+
+ private PrimitiveComponentType createAWhiteboardHost() {
+ return new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(HostImpl.class.getName())
+ .addHandler(new Whiteboard()
+ .onArrival("arrival")
+ .onDeparture("departure")
+ .setFilter("(foo=foo)")
+ );
+ }
+
+ private PrimitiveComponentType createASecondWhiteboardHost() {
+ return new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(HostImpl.class.getName())
+ .addHandler(new Whiteboard()
+ .onArrival("arrival")
+ .onDeparture("departure")
+ .setFilter("(foo=foo)")
+ )
+ .addHandler(new Whiteboard()
+ .onArrival("arrival")
+ .onDeparture("departure")
+ .setFilter("(foo=bar)")
+ .onModification("modification")
+ );
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/PrimitiveComponentTest.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/PrimitiveComponentTest.java
new file mode 100644
index 0000000..e9b7b22
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/PrimitiveComponentTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.api.Dependency;
+import org.apache.felix.ipojo.api.PrimitiveComponentType;
+import org.apache.felix.ipojo.api.Service;
+import org.apache.felix.ipojo.api.SingletonComponentType;
+import org.apache.felix.ipojo.runtime.core.api.components.FooImpl;
+import org.apache.felix.ipojo.runtime.core.api.components.MyComponentImpl;
+import org.apache.felix.ipojo.runtime.core.api.components.PlainHelloImpl;
+import org.apache.felix.ipojo.runtime.core.api.services.Foo;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.io.IOException;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+
+public class PrimitiveComponentTest extends Common {
+
+ private BundleContext context;
+
+ @Before
+ public void setUp() {
+ context = getContext();
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ return super.config();
+ }
+
+ @Test
+ public void createAServiceProvider() throws Exception {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci;
+
+ PrimitiveComponentType type = createAProvider();
+ ci = type.createInstance();
+ assertThat("Ci is valid", ci.getState(), is(ComponentInstance.VALID));
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Foo.class
+ .getName(), ci.getInstanceName());
+ assertThat(ref, is(notNullValue()));
+
+ }
+
+ @Test
+ public void killTheFactory() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci = null;
+
+ PrimitiveComponentType type = createAProvider();
+ ci = type.createInstance();
+ assertThat("Ci is valid", ci.getState(), is(ComponentInstance.VALID));
+ assertThat(ipojoHelper.isServiceAvailableByName(Foo.class.getName(), ci
+ .getInstanceName()), is(true));
+ type.stop();
+ assertThat("Ci is disposed", ci.getState(),
+ is(ComponentInstance.DISPOSED));
+ assertThat(ipojoHelper.isServiceAvailableByName(Foo.class.getName(), ci
+ .getInstanceName()), is(false));
+
+ }
+
+ @Test
+ public void createAServiceCons() throws Exception {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci = null;
+
+ PrimitiveComponentType type = createAConsumer();
+ ci = type.createInstance();
+ assertThat("Ci is invalid", ci.getState(),
+ is(ComponentInstance.INVALID));
+
+ }
+
+ @Test
+ public void createBoth() throws Exception {
+ ComponentInstance cons = createAConsumer().createInstance();
+ // cons is invalid
+ assertThat("cons is invalid", cons.getState(), is(ComponentInstance.INVALID));
+
+ ComponentInstance prov = createAProvider().createInstance();
+ assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
+ assertThat("cons is valid", cons.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ @Test
+ public void createTwoCons() throws Exception {
+ ComponentInstance cons1 = createAConsumer().createInstance();
+ // cons is invalid
+ assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
+
+ ComponentInstance prov = createAProvider().createInstance();
+ assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
+ assertThat("cons is valid", cons1.getState(), is(ComponentInstance.VALID));
+
+ ComponentInstance cons2 = createAnOptionalConsumer().createInstance();
+
+ assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
+
+ prov.stop();
+ assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
+ assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
+ }
+
+ @Test
+ public void notManipulatedComponent() throws Exception {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci;
+
+ PrimitiveComponentType x= new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(PlainHelloImpl.class.getName())
+ .setValidateMethod("start")
+ .setInvalidateMethod("stop");
+
+ x.start();
+
+ assertThat(x, is(notNullValue()));
+ assertThat(x.getFactory().getState(), is(Factory.VALID));
+
+ ci = x.createInstance();
+ ci.start();
+ assertThat(ci.getState(), is(ComponentInstance.VALID));
+
+ x.stop();
+ }
+
+ private PrimitiveComponentType createAProvider() {
+ return new PrimitiveComponentType()
+ .setBundleContext(context)
+ .setClassName(FooImpl.class.getName())
+ .addService(new Service()); // Provide the FooService
+ }
+
+ private PrimitiveComponentType createAConsumer() {
+ return new SingletonComponentType()
+ .setBundleContext(context)
+ .setClassName(MyComponentImpl.class.getName())
+ .addDependency(new Dependency().setField("myFoo"))
+ .setValidateMethod("start");
+ }
+
+ private PrimitiveComponentType createAnOptionalConsumer() {
+ return new SingletonComponentType()
+ .setBundleContext(context)
+ .setComponentTypeName("cons.optional")
+ .setClassName(MyComponentImpl.class.getName())
+ .addDependency(new Dependency().setField("myFoo").setOptional(true))
+ .setValidateMethod("start");
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/SingletonComponentTest.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/SingletonComponentTest.java
new file mode 100644
index 0000000..9c5f8f8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/SingletonComponentTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.api.Dependency;
+import org.apache.felix.ipojo.api.PrimitiveComponentType;
+import org.apache.felix.ipojo.api.Service;
+import org.apache.felix.ipojo.api.SingletonComponentType;
+import org.apache.felix.ipojo.runtime.core.api.components.FooImpl;
+import org.apache.felix.ipojo.runtime.core.api.components.MyComponentImpl;
+import org.apache.felix.ipojo.runtime.core.api.services.Foo;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+
+public class SingletonComponentTest extends Common {
+
+ private BundleContext context;
+
+ @Before
+ public void setUp() {
+ context = getContext();
+ }
+
+ @Test
+ public void createAServiceProvider() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci = null;
+
+ SingletonComponentType type = createAProvider();
+ ci = type.create();
+ assertThat("Ci is valid", ci.getState(), is(ComponentInstance.VALID));
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Foo.class
+ .getName(), ci.getInstanceName());
+ assertThat(ref, is(notNullValue()));
+ type.disposeInstance(ci);
+
+ }
+
+ @Test
+ public void killTheFactory() throws Exception {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci = null;
+ SingletonComponentType type = createAProvider();
+ ci = type.create();
+ assertThat("Ci is valid", ci.getState(), is(ComponentInstance.VALID));
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Foo.class
+ .getName(), ci.getInstanceName());
+ assertThat(ref, is(notNullValue()));
+ type.stop();
+ assertThat("Ci is disposed", ci.getState(),
+ is(ComponentInstance.DISPOSED));
+ assertThat(ipojoHelper.isServiceAvailableByName(Foo.class.getName(), ci
+ .getInstanceName()), is(false));
+ }
+
+ @Test
+ public void createAServiceCons() throws Exception {
+ assertThat(context, is(notNullValue()));
+ ComponentInstance ci = null;
+
+ SingletonComponentType type = createAConsumer();
+ ci = type.create();
+ assertThat("Ci is invalid", ci.getState(),
+ is(ComponentInstance.INVALID));
+ type.stop();
+ }
+
+ @Test
+ public void createBoth() throws Exception {
+ SingletonComponentType consFactory = createAConsumer();
+ ComponentInstance cons = consFactory.create();
+ // cons is invalid
+ assertThat("cons is invalid", cons.getState(), is(ComponentInstance.INVALID));
+
+ SingletonComponentType provFactory = createAProvider();
+ ComponentInstance prov = provFactory.create();
+ assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
+ assertThat("cons is valid", cons.getState(), is(ComponentInstance.VALID));
+ consFactory.stop();
+ provFactory.stop();
+ }
+
+ @Test
+ public void createTwoCons() throws Exception {
+ SingletonComponentType consFactory = createAConsumer();
+ ComponentInstance cons1 = createAConsumer().create();
+ // cons is invalid
+ assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
+
+ ComponentInstance prov = createAProvider().create();
+ assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
+ assertThat("cons is valid", cons1.getState(), is(ComponentInstance.VALID));
+
+ ComponentInstance cons2 = createAnOptionalConsumer().create();
+
+ assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
+
+ prov.stop();
+ assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
+ assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
+ }
+
+ @Test
+ // @Ignore("We can't test as the MyComponentImpl must be manipulated before creating the object")
+ public void setObject() throws Exception {
+ ComponentInstance cons = createAConsumer().setObject(new MyComponentImpl(5)).create();
+ // cons is invalid
+ assertThat("cons is invalid", cons.getState(), is(ComponentInstance.INVALID));
+
+ ComponentInstance prov = createAProvider().create();
+ assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
+ assertThat("cons is valid", cons.getState(), is(ComponentInstance.VALID));
+
+ }
+
+ private SingletonComponentType createAProvider() {
+ PrimitiveComponentType type = new SingletonComponentType()
+ .setBundleContext(context)
+ .setClassName(FooImpl.class.getName())
+ .addService(new Service()); // Provide the FooService
+
+ return (SingletonComponentType) type;
+ }
+
+ private SingletonComponentType createAConsumer() {
+ PrimitiveComponentType type = new SingletonComponentType()
+ .setBundleContext(context)
+ .setClassName(MyComponentImpl.class.getName())
+ .setComponentTypeName("singleton.cons")
+ .addDependency(new Dependency().setField("myFoo"))
+ .setValidateMethod("start");
+
+ return (SingletonComponentType) type;
+ }
+
+ private SingletonComponentType createAnOptionalConsumer() {
+ PrimitiveComponentType type = new SingletonComponentType()
+ .setBundleContext(context)
+ .setClassName(MyComponentImpl.class.getName())
+ .addDependency(new Dependency().setField("myFoo").setOptional(true))
+ .setComponentTypeName("singleton.optional.consumer")
+ .setValidateMethod("start");
+
+ return (SingletonComponentType) type;
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Whiteboard.java b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Whiteboard.java
new file mode 100644
index 0000000..77caf6b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-api-test/src/test/java/org/apache/felix/ipojo/runtime/core/api/Whiteboard.java
@@ -0,0 +1,90 @@
+/*
+ * 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.api;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class Whiteboard implements HandlerConfiguration {
+
+ public static final String NAME = "wbp";
+
+ public static final String NAMESPACE = "org.apache.felix.ipojo.whiteboard";
+
+ private String arrival;
+
+ private String departure;
+
+ private String modification;
+
+ private String filter;
+
+ public Whiteboard onArrival(String method) {
+ arrival = method;
+ return this;
+ }
+
+ public Whiteboard onDeparture(String method) {
+ departure = method;
+ return this;
+ }
+
+ public Whiteboard onModification(String method) {
+ modification = method;
+ return this;
+ }
+
+ public Whiteboard setFilter(String fil) {
+ filter = fil;
+ return this;
+ }
+
+ public Element getElement() {
+ ensureValidity();
+ // Create the root element.
+ Element element = new Element(NAME, NAMESPACE);
+ // Mandatory attributes
+ element.addAttribute(new Attribute("onArrival", arrival));
+ element.addAttribute(new Attribute("onDeparture", departure));
+ element.addAttribute(new Attribute("filter", filter));
+
+ // Optional attribute
+ if (modification != null) {
+ element.addAttribute(new Attribute("onModification", modification));
+ }
+
+ return element;
+ }
+
+ private void ensureValidity() {
+ if (arrival == null) {
+ throw new IllegalStateException("The whiteboard pattern configuration must have a onArrival method");
+ }
+ if (departure == null) {
+ throw new IllegalStateException("The whiteboard pattern configuration must have a onDeparture method");
+ }
+ if (filter == null) {
+ throw new IllegalStateException("The whiteboard pattern configuration must have a filter");
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/pom.xml b/ipojo/runtime/core-it/ipojo-compatibility-test/pom.xml
new file mode 100644
index 0000000..471cf75
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ipojo-compatibility-test</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceConsumer.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceConsumer.java
new file mode 100644
index 0000000..a6a7b95
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceConsumer.java
@@ -0,0 +1,50 @@
+/*
+ * 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.compatibility.ipojo;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.apache.felix.ipojo.test.compatibility.service.HelloService;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Hello Service Provider with iPOJO.
+ */
+@Component
+@Provides
+@Instantiate
+public class HelloServiceConsumer implements CheckService {
+
+ @Requires
+ private HelloService hello;
+
+ @Override
+ public Map<String, Object> data() {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ map.put("result", hello.hello("john doe"));
+ map.put("object", hello);
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceProvider.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceProvider.java
new file mode 100644
index 0000000..11f4f49
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/ipojo/HelloServiceProvider.java
@@ -0,0 +1,44 @@
+/*
+ * 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.compatibility.ipojo;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.test.compatibility.service.HelloService;
+
+/**
+ * Hello Service Provider with iPOJO.
+ */
+@Component
+@Provides
+@Instantiate
+public class HelloServiceProvider implements HelloService {
+
+ /**
+ * A very original implementation.
+ * @param name the name
+ * @return hello $name
+ */
+ @Override
+ public String hello(String name) {
+ return "hello " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceConsumer.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceConsumer.java
new file mode 100644
index 0000000..36e05d8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * 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.compatibility.scr;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.apache.felix.ipojo.test.compatibility.service.HelloService;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Hello Service Provider with SCR.
+ */
+public class HelloServiceConsumer implements CheckService {
+
+ private HelloService hello;
+
+ @Override
+ public Map<String, Object> data() {
+ synchronized (this) {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ if (hello != null) {
+ map.put("result", hello.hello("john doe"));
+ map.put("object", hello);
+ }
+ return map;
+ }
+ }
+
+ public void bindHello(HelloService h) {
+ synchronized (this) {
+ hello = h;
+ }
+ }
+
+ public void unbindHello(HelloService h) {
+ synchronized (this) {
+ hello = null;
+ }
+ }
+
+ /**
+ * Used by blueprint...
+ *
+ * @param h the hello service instance.
+ */
+ public void setHello(HelloService h) {
+ hello = h;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceProvider.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceProvider.java
new file mode 100644
index 0000000..93579ea
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/scr/HelloServiceProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.compatibility.scr;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.test.compatibility.service.HelloService;
+
+/**
+ * Hello Service Provider with SCR.
+ */
+public class HelloServiceProvider implements HelloService {
+
+ /**
+ * A very original implementation.
+ * @param name the name
+ * @return hello $name
+ */
+ @Override
+ public String hello(String name) {
+ return "hello " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/CheckService.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/CheckService.java
new file mode 100644
index 0000000..08131ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.compatibility.service;
+
+import java.util.Map;
+
+/**
+ * A service used to check the correct invocation.
+ */
+public interface CheckService {
+
+ public Map<String, Object> data();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/HelloService.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/HelloService.java
new file mode 100644
index 0000000..50c4781
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/java/org/apache/felix/ipojo/test/compatibility/service/HelloService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.compatibility.service;
+
+/**
+ * A simple service that will be implemented with several technology.
+ */
+public interface HelloService {
+
+ public String hello(String name);
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloConsumer.xml b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloConsumer.xml
new file mode 100644
index 0000000..4f86166
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloConsumer.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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">
+
+ <!-- Reuse the same implementation as for SCR -->
+ <bean id="consumer" class="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceConsumer">
+ <property name="hello" ref="helloRef"/>
+ </bean>
+
+ <service id="service" ref="consumer" interface="org.apache.felix.ipojo.test.compatibility.service.CheckService"/>
+ <reference id="helloRef" availability="mandatory"
+ interface="org.apache.felix.ipojo.test.compatibility.service.HelloService"/>
+
+</blueprint>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloProvider.xml b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloProvider.xml
new file mode 100644
index 0000000..9aa5be9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/blueprint/HelloProvider.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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">
+
+ <!-- Reuse the same implementation as for SCR -->
+ <bean id="provider" class="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceProvider">
+ </bean>
+
+ <service id="service" ref="provider" interface="org.apache.felix.ipojo.test.compatibility.service.HelloService"/>
+
+</blueprint>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloConsumer.xml b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloConsumer.xml
new file mode 100644
index 0000000..d71b6ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloConsumer.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<component name="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceConsumer" immediate="true">
+ <implementation class="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceConsumer"/>
+ <service>
+ <provide interface="org.apache.felix.ipojo.test.compatibility.service.CheckService"/>
+ </service>
+ <reference name="hello"
+ interface="org.apache.felix.ipojo.test.compatibility.service.HelloService"
+ cardinality="1..1"
+ policy="dynamic"
+ bind="bindHello"
+ unbind="unbindHello"
+ />
+</component>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloProvider.xml b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloProvider.xml
new file mode 100644
index 0000000..a8e048a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/main/resources/scr/HelloProvider.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<component name="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceProvider" immediate="true">
+ <implementation class="org.apache.felix.ipojo.test.compatibility.scr.HelloServiceProvider" />
+ <service>
+ <provide interface="org.apache.felix.ipojo.test.compatibility.service.HelloService" />
+ </service>
+</component>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/Common.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/Common.java
new file mode 100644
index 0000000..9e26d3d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/Common.java
@@ -0,0 +1,307 @@
+/*
+ * 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.compatibility;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.test.compatibility.ipojo.HelloServiceConsumer;
+import org.apache.felix.ipojo.test.compatibility.ipojo.HelloServiceProvider;
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.apache.felix.ipojo.test.compatibility.service.HelloService;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.helpers.FrameworkHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.*;
+import java.net.MalformedURLException;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Configure the tests.
+ */
+public abstract class Common extends BaseTest {
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+
+ @Override
+ protected Option[] getCustomOptions() {
+ Option[] options = new Option[] {
+ service(),
+ wrappedBundle(maven("org.easytesting", "fest-assert").versionAsInProject()),
+ wrappedBundle(maven("org.easytesting", "fest-util").versionAsInProject())
+ };
+
+ return OptionUtils.combine(options, bundles());
+ }
+
+ public abstract Option[] bundles();
+
+ /**
+ * Package the service interfaces.
+ */
+ public Option service() {
+ File out = new File("target/bundles/service.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(CheckService.class);
+ bundle.add(HelloService.class);
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "services")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.test.compatibility.service")
+ .build(withBnd());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * iPOJO Hello Service Provider.
+ */
+ public Option iPOJOHelloProvider() {
+ File out = new File("target/bundles/hello-provider-ipojo.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(HelloServiceProvider.class);
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "iPOJO-Hello-Provider")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ .build(IPOJOStrategy.withiPOJO());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * iPOJO Hello Service Provider.
+ */
+ public Option iPOJOHelloConsumer() {
+ File out = new File("target/bundles/hello-consumer-ipojo.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(HelloServiceConsumer.class);
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "iPOJO-Hello-Consumer")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ .build(IPOJOStrategy.withiPOJO());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Package the SCR Hello Service Provider.
+ */
+ public Option SCRHelloProvider() {
+ File out = new File("target/bundles/hello-provider-scr.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ File metadata = new File("src/main/resources/scr", "HelloProvider.xml");
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(org.apache.felix.ipojo.test.compatibility.scr.HelloServiceProvider.class);
+ try {
+ bundle.add("scr/provider.xml", new FileInputStream(metadata));
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Cannot find XML metadata : " + metadata.getAbsolutePath());
+ }
+
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "hello-provider-scr")
+ //.set(Constants.IMPORT_PACKAGE, "*")
+ .set("Service-Component", "scr/provider.xml")
+ .build(withBnd());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public Option SCRHelloConsumer() {
+ File out = new File("target/bundles/hello-consumer-scr.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ File metadata = new File("src/main/resources/scr", "HelloConsumer.xml");
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(org.apache.felix.ipojo.test.compatibility.scr.HelloServiceConsumer.class);
+ try {
+ bundle.add("scr/consumer.xml", new FileInputStream(metadata));
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Cannot find XML metadata : " + metadata.getAbsolutePath());
+ }
+
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "hello-consumer-scr")
+ // .set(Constants.IMPORT_PACKAGE, "*")
+ .set("Service-Component", "scr/consumer.xml")
+ .build(withBnd());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Package the Blueprint Hello Service Provider.
+ */
+ public Option BPHelloProvider() {
+ File out = new File("target/bundles/hello-provider-blueprint.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ File metadata = new File("src/main/resources/blueprint", "HelloProvider.xml");
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(org.apache.felix.ipojo.test.compatibility.scr.HelloServiceProvider.class);
+ try {
+ bundle.add("blueprint/provider.xml", new FileInputStream(metadata));
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Cannot find XML metadata : " + metadata.getAbsolutePath());
+ }
+
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "hello-provider-blueprint")
+ // .set(Constants.IMPORT_PACKAGE, "*")
+ .set("Bundle-Blueprint", "blueprint/provider.xml")
+ .build(withBnd());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public Option BPHelloConsumer() {
+ File out = new File("target/bundles/hello-consumer-blueprint.jar");
+ if (out.exists()) {
+ try {
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ // Ignore it.
+ }
+ }
+
+ File metadata = new File("src/main/resources/blueprint", "HelloConsumer.xml");
+
+ TinyBundle bundle = TinyBundles.bundle();
+ bundle.add(org.apache.felix.ipojo.test.compatibility.scr.HelloServiceConsumer.class);
+ try {
+ bundle.add("blueprint/consumer.xml", new FileInputStream(metadata));
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Cannot find XML metadata : " + metadata.getAbsolutePath());
+ }
+
+ InputStream inputStream = bundle
+ .set(Constants.BUNDLE_SYMBOLICNAME, "hello-consumer-blueprint")
+ // .set(Constants.IMPORT_PACKAGE, "*")
+ .set("Bundle-Blueprint", "blueprint/consumer.xml")
+ .build(withBnd());
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public boolean isEquinox() {
+ if (context != null) {
+ return FrameworkHelper.isEquinox(context) || context.toString().contains("eclipse");
+ } else {
+ String pf = System.getProperty("pax.exam.framework");
+ return pf != null && pf.equalsIgnoreCase("equinox");
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByAriesBlueprint1_1_0.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByAriesBlueprint1_1_0.java
new file mode 100644
index 0000000..36d41d8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByAriesBlueprint1_1_0.java
@@ -0,0 +1,60 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Aries Blueprint 1.0.1
+ * iPOJO provider is consumed by a component using Blueprint.
+ *
+ * This test is intended to pass on Felix, KF and Equinox
+ */
+public class TestBeingConsumedByAriesBlueprint1_1_0 extends Common {
+
+ public static final String BP_ARTIFACTID = "org.apache.aries.blueprint";
+ public static final String BP_VERSION = "1.1.0";
+ public static final String BP_GROUPID = "org.apache.aries.blueprint";
+
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(maven(BP_GROUPID, BP_ARTIFACTID, BP_VERSION).getURL()),
+ bundle(maven("org.apache.aries.proxy", "org.apache.aries.proxy", "1.0.1").getURL()),
+ bundle(maven("org.apache.aries", "org.apache.aries.util", "1.1.0").getURL()),
+ BPHelloConsumer(),
+ iPOJOHelloProvider()
+ };
+ }
+
+ @Test
+ public void test() {
+ CheckService checker = osgiHelper.waitForService(CheckService.class, null, 5000, false);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByEquinoxSCR1_4_100.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByEquinoxSCR1_4_100.java
new file mode 100644
index 0000000..34d3177
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByEquinoxSCR1_4_100.java
@@ -0,0 +1,66 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+
+/**
+ * Check a configuration using Equinox SCR 1.4.100 (Declarative Services).
+ * iPOJO provider is consumed by a component using SCR.
+ *
+ *
+ * This test is intended to pass on Equinox only.
+ */
+public class TestBeingConsumedByEquinoxSCR1_4_100 extends Common {
+
+ public static String DS_URL = "http://people.apache.org/~clement/ipojo/bundle4tests/org.eclipse.equinox.ds_1.4.101.v20130813-1853.jar";
+
+ public static String UTILS_URL = "http://people.apache.org/~clement/ipojo/bundle4tests/org.eclipse.equinox.util_1.0.500.v20130404-1337.jar";
+
+ @Override
+ public Option[] bundles() {
+ // We must not deploy the Equinox DS on Felix and KF
+ if (! isEquinox()) {
+ return new Option[0];
+ }
+ return new Option[] {
+ bundle(DS_URL),
+ bundle(UTILS_URL),
+ iPOJOHelloProvider(),
+ SCRHelloConsumer()
+ };
+ }
+
+ @Test
+ public void test() {
+ if (! isEquinox()) {
+ System.out.println("Test executed on Equinox only");
+ return;
+ }
+ CheckService checker = osgiHelper.waitForService(CheckService.class, null, 1000);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByFelixSCR1_6_2.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByFelixSCR1_6_2.java
new file mode 100644
index 0000000..7cf8501
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByFelixSCR1_6_2.java
@@ -0,0 +1,57 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Felix SCR 1.6.2.
+ * iPOJO provider is consumed by a component using SCR.
+ *
+ * This test is intended to pass on Felix, KF and Equinox
+ */
+public class TestBeingConsumedByFelixSCR1_6_2 extends Common {
+
+ public static final String SCR_ARTIFACTID = "org.apache.felix.scr";
+ public static final String SCR_VERSION = "1.6.2";
+ public static final String SCR_GROUPID = "org.apache.felix";
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(maven(SCR_GROUPID, SCR_ARTIFACTID, SCR_VERSION).getURL()),
+ SCRHelloConsumer(),
+ iPOJOHelloProvider()
+ };
+ }
+
+ @Test
+ public void test() {
+ CheckService checker = osgiHelper.waitForService(CheckService.class, null, 1000);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByKnopflerfishSCR4_0_2.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByKnopflerfishSCR4_0_2.java
new file mode 100644
index 0000000..90befb6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestBeingConsumedByKnopflerfishSCR4_0_2.java
@@ -0,0 +1,65 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Knopflerfish SCR 4.0.2
+ * iPOJO provider is consumed by a component using SCR.
+ *
+ * This test is intended to pass on KF only
+ */
+public class TestBeingConsumedByKnopflerfishSCR4_0_2 extends Common {
+
+ public static final String SCR_URL = "http://www.knopflerfish.org/releases/4.0" +
+ ".0/maven2/org/knopflerfish/bundle/component/4.0.2/component-4.0.2.jar";
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(SCR_URL),
+ bundle("http://www.knopflerfish.org/releases/4.0.0/maven2/org/knopflerfish/bundle/cm-API/4.0" +
+ ".1/cm-API-4.0.1.jar"),
+ bundle("http://www.knopflerfish.org/releases/4.0.0/maven2/org/knopflerfish/bundle/kxml-LIB/2.3.0" +
+ ".kf4-001/kxml-LIB-2.3.0.kf4-001.jar"),
+ SCRHelloConsumer(),
+ iPOJOHelloProvider()
+ };
+ }
+
+ @Test
+ public void test() {
+ if (! isKnopflerfish()) {
+ System.out.println("Test ignored - running only on Knopflerfish");
+ return;
+ }
+
+ CheckService checker = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingAriesBlueprint1_1_0.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingAriesBlueprint1_1_0.java
new file mode 100644
index 0000000..298df42
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingAriesBlueprint1_1_0.java
@@ -0,0 +1,61 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Aries Blueprint 1.1.0
+ * iPOJO consumer is bound to a Hello Service implementation using Blueprint.
+ *
+ * This test is intended to pass on Felix, KF and Equinox
+ */
+public class TestConsumingProviderUsingAriesBlueprint1_1_0 extends Common {
+
+ public static final String BP_ARTIFACTID = "org.apache.aries.blueprint";
+ public static final String BP_VERSION = "1.1.0";
+ public static final String BP_GROUPID = "org.apache.aries.blueprint";
+
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(maven(BP_GROUPID, BP_ARTIFACTID, BP_VERSION).getURL()),
+ bundle(maven("org.apache.aries.proxy", "org.apache.aries.proxy", "1.0.1").getURL()),
+ bundle(maven("org.apache.aries", "org.apache.aries.util", "1.1.0").getURL()),
+ BPHelloProvider(),
+ iPOJOHelloConsumer()
+ };
+ }
+
+ @Test
+ public void test() {
+ osgiHelper.waitForService(CheckService.class, null, 10000);
+ CheckService checker = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingEquinoxSCR1_4_100.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingEquinoxSCR1_4_100.java
new file mode 100644
index 0000000..b7287ee
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingEquinoxSCR1_4_100.java
@@ -0,0 +1,68 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+import org.osgi.framework.Bundle;
+import org.ow2.chameleon.testing.helpers.Dumps;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Equinox SCR 1.4.100 (Declarative Services).
+ * iPOJO consumer is bound to a Hello Service implementation using SCR.
+ *
+ *
+ * This test is intended to pass on Equinox only.
+ */
+public class TestConsumingProviderUsingEquinoxSCR1_4_100 extends Common {
+
+ public static String DS_URL = "http://people.apache.org/~clement/ipojo/bundle4tests/org.eclipse.equinox.ds_1.4.101.v20130813-1853.jar";
+
+ public static String UTILS_URL = "http://people.apache.org/~clement/ipojo/bundle4tests/org.eclipse.equinox.util_1.0.500.v20130404-1337.jar";
+
+ @Override
+ public Option[] bundles() {
+ if (! isEquinox()) {
+ return new Option[0];
+ }
+ return new Option[] {
+ bundle(DS_URL),
+ bundle(UTILS_URL),
+ SCRHelloProvider(),
+ iPOJOHelloConsumer()
+ };
+ }
+
+ @Test
+ public void test() {
+ if (! isEquinox()) {
+ System.out.println("Test executed on Equinox only");
+ return;
+ }
+ CheckService checker = osgiHelper.waitForService(CheckService.class, null, 1000);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingFelixSCR1_6_2.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingFelixSCR1_6_2.java
new file mode 100644
index 0000000..639c06f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingFelixSCR1_6_2.java
@@ -0,0 +1,58 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+
+/**
+ * Check a configuration using Felix SCR 1.6.2.
+ * iPOJO consumer is bound to a Hello Service implementation using SCR.
+ *
+ *
+ * This test is intended to pass on Felix, KF and Equinox
+ */
+public class TestConsumingProviderUsingFelixSCR1_6_2 extends Common {
+
+ public static final String SCR_ARTIFACTID = "org.apache.felix.scr";
+ public static final String SCR_VERSION = "1.6.2";
+ public static final String SCR_GROUPID = "org.apache.felix";
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(maven(SCR_GROUPID, SCR_ARTIFACTID, SCR_VERSION).getURL()),
+ SCRHelloProvider(),
+ iPOJOHelloConsumer()
+ };
+ }
+
+ @Test
+ public void test() {
+ CheckService checker = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingKnopflerfishSCR4_0_2.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingKnopflerfishSCR4_0_2.java
new file mode 100644
index 0000000..1932415
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestConsumingProviderUsingKnopflerfishSCR4_0_2.java
@@ -0,0 +1,64 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+
+/**
+ * Check a configuration using Knopflerfish SCR 4.0.2
+ * iPOJO consumer is bound to a Hello Service implementation using SCR.
+ *
+ *
+ * This test is intended to pass on KF only
+ */
+public class TestConsumingProviderUsingKnopflerfishSCR4_0_2 extends Common {
+
+ public static final String SCR_URL = "http://www.knopflerfish.org/releases/4.0" +
+ ".0/maven2/org/knopflerfish/bundle/component/4.0.2/component-4.0.2.jar";
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ bundle(SCR_URL),
+ bundle("http://www.knopflerfish.org/releases/4.0.0/maven2/org/knopflerfish/bundle/cm-API/4.0" +
+ ".1/cm-API-4.0.1.jar"),
+ bundle("http://www.knopflerfish.org/releases/4.0.0/maven2/org/knopflerfish/bundle/kxml-LIB/2.3.0" +
+ ".kf4-001/kxml-LIB-2.3.0.kf4-001.jar"),
+ SCRHelloProvider(),
+ iPOJOHelloConsumer()
+ };
+ }
+
+ @Test
+ public void test() {
+ if (! isKnopflerfish()) {
+ System.out.println("Test ignored - running only on Knopflerfish");
+ return;
+ }
+ CheckService checker = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestiPOJOOnly.java b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestiPOJOOnly.java
new file mode 100644
index 0000000..beb3623
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-compatibility-test/src/test/java/org/apache/felix/ipojo/test/compatibility/TestiPOJOOnly.java
@@ -0,0 +1,49 @@
+/*
+ * 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.compatibility;
+
+import org.apache.felix.ipojo.test.compatibility.service.CheckService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Check a configuration with iPOJO used for the provider and consumer.
+ *
+ * This test is intended to pass on Felix, KF and Equinox
+ */
+public class TestiPOJOOnly extends Common {
+
+ @Override
+ public Option[] bundles() {
+ return new Option[] {
+ iPOJOHelloConsumer(),
+ iPOJOHelloProvider(),
+ };
+ }
+
+ @Test
+ public void test() {
+ CheckService checker = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(checker).isNotNull();
+ assertThat(checker.data().get("result")).isEqualTo("hello john doe");
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-annotations-test/pom.xml
new file mode 100644
index 0000000..644a5dc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-annotations-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/Foo.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/Foo.java
new file mode 100644
index 0000000..4556678
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/Foo.java
@@ -0,0 +1,29 @@
+/*
+ * 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 foo;
+
+
+/**
+ * Creates a simple annotation to create the processing of non-matching
+ * annotations
+ */
+public @interface Foo {
+ String bar();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/RGB.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/RGB.java
new file mode 100644
index 0000000..77a1631
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/RGB.java
@@ -0,0 +1,28 @@
+/*
+ * 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 foo;
+
+/**
+ * Checks the enum support in custom handler.
+ */
+public enum RGB {
+
+ RED, GREEN, BLUE
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/ipojo/IPOJOFoo.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/ipojo/IPOJOFoo.java
new file mode 100644
index 0000000..b2f365f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/foo/ipojo/IPOJOFoo.java
@@ -0,0 +1,35 @@
+/*
+ * 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 foo.ipojo;
+
+
+import foo.RGB;
+
+/**
+ * Creates a simple annotation to create the processing of matching
+ * annotations
+ */
+public @interface IPOJOFoo {
+ String bar();
+
+ RGB rgb() default RGB.BLUE;
+
+ RGB[] colors() default {};
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AggregateDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AggregateDependency.java
new file mode 100644
index 0000000..cd6fbc7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AggregateDependency.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Unbind;
+
+@Component
+public class AggregateDependency {
+
+ @Unbind(aggregate=true)
+ public void unbindBar() { }
+ @Bind
+ public void bindBar() { }
+
+ @Unbind
+ public void unbindBaz() { }
+ @Bind(aggregate=true)
+ public void bindBaz() { }
+
+ @Unbind(aggregate=true, id="unbindonly")
+ public void unbind() { }
+
+ @Bind(aggregate=true, id="bindonly")
+ public void bind() { }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Arch.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Arch.java
new file mode 100644
index 0000000..b370979
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Arch.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(architecture=true)
+public class Arch {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ComponentTypeVersion.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ComponentTypeVersion.java
new file mode 100644
index 0000000..2fea578
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ComponentTypeVersion.java
@@ -0,0 +1,28 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+
+@Component(version="1.0.0")
+public class ComponentTypeVersion {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CustomAnnotationWithEnum.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CustomAnnotationWithEnum.java
new file mode 100644
index 0000000..174b42a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CustomAnnotationWithEnum.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import foo.RGB;
+import foo.ipojo.IPOJOFoo;
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component
+@IPOJOFoo(bar="bar", rgb = RGB.RED, colors = {RGB.BLUE, RGB.RED})
+public class CustomAnnotationWithEnum {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DefaultImplementationDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DefaultImplementationDependency.java
new file mode 100644
index 0000000..cf3a098
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DefaultImplementationDependency.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class DefaultImplementationDependency {
+
+ @Requires(defaultimplementation=ProvidesSimple.class, optional=true)
+ public FooService fs;
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Dependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Dependency.java
new file mode 100644
index 0000000..b34ad68
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Dependency.java
@@ -0,0 +1,103 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Modified;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class Dependency {
+
+ @Requires
+ public FooService fs;
+
+ @Unbind
+ public void unbindBar() {
+
+ }
+
+ @Bind
+ public void bindBar() {
+
+ }
+
+ @Unbind
+ public void unbindBaz() {
+
+ }
+
+ @Bind
+ public void bindBaz() {
+
+ }
+
+
+ @Requires
+ public FooService fs2;
+
+ @Bind(id="fs2")
+ public void bindFS2() {
+
+ }
+
+ @Unbind(id="fs2")
+ public void unbindFS2() {
+
+ }
+
+ @Requires(id="inv")
+ public FooService fs2inv;
+
+ @Bind(id="inv")
+ public void bindFS2Inv() {
+
+ }
+
+ @Unbind(id="inv")
+ public void unbindFS2Inv() {
+
+ }
+
+ @Bind(id="mod")
+ public void bindMod() {
+
+ }
+
+ @Unbind(id="mod")
+ public void unbindMod() {
+
+ }
+
+ @Modified(id="mod")
+ public void modifiedMod() {
+
+ }
+
+
+ @Requires(proxy=false, id="notproxied")
+ FooService myFoo;
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DependencyUsingSpecification.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DependencyUsingSpecification.java
new file mode 100644
index 0000000..42d6bb9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DependencyUsingSpecification.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.*;
+import java.util.Properties;
+
+@Component
+@Provides
+public class DependencyUsingSpecification implements CheckService {
+
+ private boolean bound = false;
+
+ @Unbind
+ public synchronized void unbindBar() {
+ bound = false;
+ }
+
+ @Bind(specification = BarService.class, optional = true)
+ public synchronized void bindBar() {
+ bound = true;
+ }
+
+ @Override
+ public boolean check() {
+ return bound;
+ }
+
+ @Override
+ public Properties getProps() {
+ return null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Factory.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Factory.java
new file mode 100644
index 0000000..097c325
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Factory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(name="factory", publicFactory=true)
+public class Factory {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryDeprecated.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryDeprecated.java
new file mode 100644
index 0000000..013e5a9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryDeprecated.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(public_factory=true)
+public class FactoryDeprecated {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethod.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethod.java
new file mode 100644
index 0000000..5072fbc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethod.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(factoryMethod="create")
+public class FactoryMethod {
+
+ public static FactoryMethod create() {
+ return new FactoryMethod();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethodDeprecated.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethodDeprecated.java
new file mode 100644
index 0000000..5d060ef
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FactoryMethodDeprecated.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(factory_method="create")
+public class FactoryMethodDeprecated {
+
+ public static FactoryMethodDeprecated create() {
+ return new FactoryMethodDeprecated();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FilteredDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FilteredDependency.java
new file mode 100644
index 0000000..f94a90c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FilteredDependency.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class FilteredDependency {
+
+ @Requires(filter="(foo=bar)")
+ public FooService fs;
+
+ @Unbind(filter="(foo=bar)")
+ public void unbindBar() { }
+ @Bind
+ public void bindBar() { }
+
+ @Unbind
+ public void unbindBaz() { }
+ @Bind(filter="(foo=bar)")
+ public void bindBaz() { }
+
+ @Requires(id="inv")
+ public FooService fs2inv;
+ @Bind(id="inv", filter="(foo=bar)")
+ public void bindFS2Inv() { }
+ @Unbind(id="inv")
+ public void unbindFS2Inv() { }
+
+ @Unbind(filter="(foo=bar)", id="unbindonly")
+ public void unbind() { }
+
+ @Bind(filter="(foo=bar)", id="bindonly")
+ public void bind() { }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FromDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FromDependency.java
new file mode 100644
index 0000000..d1002f7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FromDependency.java
@@ -0,0 +1,83 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class FromDependency {
+
+ @Requires(from="X")
+ public FooService fs;
+
+ @Unbind
+ public void unbindBar() {
+
+ }
+
+ @Bind
+ public void bindBar() {
+
+ }
+
+ @Unbind(from="both")
+ public void unbindBaz() {
+
+ }
+
+ @Bind(from="both")
+ public void bindBaz() {
+
+ }
+
+
+ @Requires
+ public FooService fs2;
+
+ @Bind(id="fs2", from="X")
+ public void bindFS2() {
+
+ }
+
+ @Unbind(id="fs2")
+ public void unbindFS2() {
+
+ }
+
+ @Requires(id="inv")
+ public FooService fs2inv;
+
+ @Bind(id="inv")
+ public void bindFS2Inv() {
+
+ }
+
+ @Unbind(id="inv", from="X")
+ public void unbindFS2Inv() {
+
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Immediate.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Immediate.java
new file mode 100644
index 0000000..c23ce4a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Immediate.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(immediate=true)
+public class Immediate {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateSimple.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateSimple.java
new file mode 100644
index 0000000..c054f33
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateSimple.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+
+
+@Instantiate
+@Component
+public class InstantiateSimple {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateWithName.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateWithName.java
new file mode 100644
index 0000000..a0f4604
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/InstantiateWithName.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+
+
+@Instantiate(name="myInstantiatedInstance")
+@Component
+public class InstantiateWithName {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Lifecycle.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Lifecycle.java
new file mode 100644
index 0000000..ecae824
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Lifecycle.java
@@ -0,0 +1,41 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Controller;
+import org.apache.felix.ipojo.annotations.Invalidate;
+import org.apache.felix.ipojo.annotations.Validate;
+
+@Component
+public class Lifecycle {
+ @Controller
+ boolean lfc;
+
+ @Validate
+ public void start() {
+
+ }
+
+ @Invalidate
+ public void stop() {
+
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ManagedServicePID.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ManagedServicePID.java
new file mode 100644
index 0000000..a3ea391
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ManagedServicePID.java
@@ -0,0 +1,93 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(managedservice="MyPID")
+public class ManagedServicePID implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MyComparator.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MyComparator.java
new file mode 100644
index 0000000..9e0b6cf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MyComparator.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components;
+
+import java.util.Comparator;
+
+public class MyComparator implements Comparator {
+
+ public int compare(Object o1, Object o2) {
+ return 0;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoAnnotation.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoAnnotation.java
new file mode 100644
index 0000000..a4fd669
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoAnnotation.java
@@ -0,0 +1,24 @@
+/*
+ * 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.test.components;
+
+public class NoAnnotation {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoArch.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoArch.java
new file mode 100644
index 0000000..f93bf91
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoArch.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(architecture=false)
+public class NoArch {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoFactory.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoFactory.java
new file mode 100644
index 0000000..612d1c0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoFactory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(name="nofactory", public_factory=false)
+public class NoFactory {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoImmediate.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoImmediate.java
new file mode 100644
index 0000000..8398195
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoImmediate.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+
+@Component(immediate=false)
+public class NoImmediate {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoPropagation.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoPropagation.java
new file mode 100644
index 0000000..d47cf23
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NoPropagation.java
@@ -0,0 +1,93 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(propagation=false)
+public class NoPropagation implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NullableDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NullableDependency.java
new file mode 100644
index 0000000..9b46855
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/NullableDependency.java
@@ -0,0 +1,36 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class NullableDependency {
+
+ @Requires(nullable=true)
+ public FooService fs;
+
+ @Requires(nullable=false)
+ public FooService fs2;
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyFoo.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyFoo.java
new file mode 100644
index 0000000..b726e8c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyFoo.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import foo.Foo;
+
+@Foo(bar="bar")
+public class OnlyFoo {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyiPOJOFoo.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyiPOJOFoo.java
new file mode 100644
index 0000000..2d85be2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OnlyiPOJOFoo.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import foo.ipojo.IPOJOFoo;
+
+@IPOJOFoo(bar="bar")
+public class OnlyiPOJOFoo {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OptionalDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OptionalDependency.java
new file mode 100644
index 0000000..c58e179
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/OptionalDependency.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class OptionalDependency {
+
+ @Requires(optional=true)
+ public FooService fs;
+
+ @Requires(optional=false)
+ public FooService fs2;
+
+ @Unbind(optional=true)
+ public void unbindBar() { }
+ @Bind
+ public void bindBar() { }
+
+ @Unbind
+ public void unbindBaz() { }
+ @Bind(optional=true)
+ public void bindBaz() { }
+
+ @Requires(id="inv")
+ public FooService fs2inv;
+ @Bind(id="inv", optional=true)
+ public void bindFS2Inv() { }
+ @Unbind(id="inv")
+ public void unbindFS2Inv() { }
+
+ @Unbind(optional=true, id="unbindonly")
+ public void unbind() { }
+
+ @Bind(optional=true, id="bindonly")
+ public void bind() { }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PIDandPropagation.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PIDandPropagation.java
new file mode 100644
index 0000000..6cfc7c6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PIDandPropagation.java
@@ -0,0 +1,94 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(managedservice="MyPID", propagation=true)
+public class PIDandPropagation implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceController.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceController.java
new file mode 100644
index 0000000..7c667a1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceController.java
@@ -0,0 +1,75 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceController;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {FooService.class, BarService.class})
+public class PSServiceController implements FooService, BarService {
+
+ @ServiceController(value=false)
+ public boolean controller;
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceControllerSpec.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceControllerSpec.java
new file mode 100644
index 0000000..e020f54
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PSServiceControllerSpec.java
@@ -0,0 +1,78 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceController;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {FooService.class, BarService.class})
+public class PSServiceControllerSpec implements FooService, BarService {
+
+ @ServiceController(value=false, specification=FooService.class)
+ public boolean controller1;
+
+ @ServiceController(value=true)
+ public boolean controller2;
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PolicyDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PolicyDependency.java
new file mode 100644
index 0000000..318cb5f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PolicyDependency.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class PolicyDependency {
+
+ @Requires(policy= BindingPolicy.STATIC)
+ public FooService fs;
+
+ @Requires(policy=BindingPolicy.DYNAMIC_PRIORITY)
+ public FooService fs2;
+
+ @Unbind(policy=BindingPolicy.STATIC)
+ public void unbindBar() { }
+ @Bind
+ public void bindBar() { }
+
+ @Unbind
+ public void unbindBaz() { }
+ @Bind(policy=BindingPolicy.STATIC)
+ public void bindBaz() { }
+
+ @Requires(id="inv", specification = FooService.class)
+ public FooService fs2inv;
+ @Bind(id="inv", policy=BindingPolicy.STATIC)
+ public void bindFS2Inv() { }
+ @Unbind(id="inv")
+ public void unbindFS2Inv() { }
+
+ @Unbind(policy=BindingPolicy.STATIC, id="unbindonly")
+ public void unbind() { }
+
+ @Bind(policy=BindingPolicy.STATIC, id="bindonly")
+ public void bind() { }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Propagation.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Propagation.java
new file mode 100644
index 0000000..afc3a97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Propagation.java
@@ -0,0 +1,94 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(propagation=true)
+public class Propagation implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PropagationandPID.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PropagationandPID.java
new file mode 100644
index 0000000..a243033
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/PropagationandPID.java
@@ -0,0 +1,94 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(managedservice="MyPID", propagation=true)
+public class PropagationandPID implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Properties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Properties.java
new file mode 100644
index 0000000..a174a0a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/Properties.java
@@ -0,0 +1,93 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class Properties implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5", mandatory=true)
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesDouble.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesDouble.java
new file mode 100644
index 0000000..92fccfa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesDouble.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides
+public class ProvidesDouble implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesProperties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesProperties.java
new file mode 100644
index 0000000..cde8d34
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesProperties.java
@@ -0,0 +1,86 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {FooService.class, BarService.class})
+public class ProvidesProperties implements FooService, BarService {
+
+ @ServiceProperty(name = "foo")
+ public int m_foo = 0;
+
+ @ServiceProperty(value = "4", mandatory=true)
+ public int bar;
+
+ @ServiceProperty(name="baz")
+ int m_baz;
+
+ @ServiceProperty
+ public int boo;
+
+ @ServiceProperty(name="baa", value="5")
+ public int m_baa;
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesQuatro.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesQuatro.java
new file mode 100644
index 0000000..dea2654
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesQuatro.java
@@ -0,0 +1,77 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {FooService.class, CheckService.class})
+public class ProvidesQuatro implements FooService, BarService, CheckService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+ public boolean check() {
+ return false;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesSimple.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesSimple.java
new file mode 100644
index 0000000..8513589
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesSimple.java
@@ -0,0 +1,70 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {FooService.class, BarService.class})
+public class ProvidesSimple implements FooService, BarService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesStaticProperties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesStaticProperties.java
new file mode 100644
index 0000000..7e44f30
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesStaticProperties.java
@@ -0,0 +1,94 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(
+ specifications= {FooService.class, BarService.class},
+ properties= {
+ @StaticServiceProperty(name="prop1", value="prop1", type="java.lang.String"),
+ @StaticServiceProperty(name="prop2", type="java.lang.String"),
+ @StaticServiceProperty(name="props", value="{prop1, prop2}", type="string[]"),
+ @StaticServiceProperty(name="mandatory1", mandatory=true, type="string")
+ })
+public class ProvidesStaticProperties implements FooService, BarService {
+
+ @ServiceProperty(name = "foo")
+ public int m_foo = 0;
+
+ @ServiceProperty(value = "4", mandatory=true)
+ public int bar;
+
+ @ServiceProperty(name="baz")
+ int m_baz;
+
+ @ServiceProperty
+ public int boo;
+
+ @ServiceProperty(name="baa", value="5")
+ public int m_baa;
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesTriple.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesTriple.java
new file mode 100644
index 0000000..30b4dc9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ProvidesTriple.java
@@ -0,0 +1,76 @@
+/*
+ * 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.test.components;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+@Provides(specifications= {CheckService.class})
+public class ProvidesTriple implements FooService, BarService, CheckService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+ public boolean check() {
+ return false;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedDependency.java
new file mode 100644
index 0000000..1997570
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedDependency.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class RankedDependency {
+
+ @Requires(comparator = MyComparator.class)
+ public FooService fs;
+
+ @Unbind(comparator = MyComparator.class)
+ public void unbindBar() {
+ }
+
+ @Bind
+ public void bindBar() {
+ }
+
+ @Unbind
+ public void unbindBaz() {
+ }
+
+ @Bind(comparator = MyComparator.class)
+ public void bindBaz() {
+ }
+
+ @Requires(id = "inv")
+ public FooService fs2inv;
+
+ @Bind(id = "inv", comparator = MyComparator.class)
+ public void bindFS2Inv() {
+ }
+
+ @Unbind(id = "inv")
+ public void unbindFS2Inv() {
+ }
+
+ @Unbind(comparator = MyComparator.class, id = "unbindonly")
+ public void unbind() {
+ }
+
+ @Bind(comparator = MyComparator.class, id = "bindonly")
+ public void bind() {
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithManagedService.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithManagedService.java
new file mode 100644
index 0000000..af1441f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithManagedService.java
@@ -0,0 +1,102 @@
+/*
+ * 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.test.components;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Updated;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component(managedservice="MyPID")
+public class UpdatedWithManagedService implements FooService, BarService {
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5")
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+ @Updated
+ public void after(Dictionary conf) {
+ // ...
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithProperties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithProperties.java
new file mode 100644
index 0000000..7ad0e99
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/UpdatedWithProperties.java
@@ -0,0 +1,104 @@
+/*
+ * 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.test.components;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Updated;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.BarService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+
+@Component
+public class UpdatedWithProperties implements FooService, BarService {
+
+ @Updated
+ public void after(Dictionary dict) {
+ // ...
+ }
+
+ @Property(name= "foo")
+ public int m_foo = 0;
+
+ @Property(value = "4")
+ public int bar;
+
+ @Property
+ public void setboo(int boo) {
+
+ }
+
+ @Property
+ public void setbaz(int baz) {
+
+ }
+
+ @Property
+ public int boo;
+
+ @Property(name="baa")
+ public int m_baa;
+
+ @Property(value="5", mandatory=true)
+ public void setbaa(int baa) {
+
+ }
+
+ public boolean foo() {
+ return false;
+ }
+
+ public java.util.Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean bar() {
+ return false;
+ }
+
+ public java.util.Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/ComponentWithProperties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/ComponentWithProperties.java
new file mode 100644
index 0000000..247809b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/ComponentWithProperties.java
@@ -0,0 +1,79 @@
+/*
+ * 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.test.components.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A component publishing a service with a static service property.
+ */
+@Component
+@Provides(properties = {
+ @StaticServiceProperty(name="property", value="value", type = "java.lang.String")
+})
+@Instantiate(name="instanceWithProperties")
+// We must avoid having such static properties:
+// Fixed in https://issues.apache.org/jira/browse/FELIX-4053
+//@StaticServiceProperty(name="property", value="value", type = "java.lang.String")
+public class ComponentWithProperties implements FooService{
+
+ // The implementation is meaningless.
+
+ @Override
+ public boolean foo() {
+ return false;
+ }
+
+ @Override
+ public Properties fooProps() {
+ return null;
+ }
+
+ @Override
+ public Boolean getObject() {
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return false;
+ }
+
+ @Override
+ public int getInt() {
+ return 0;
+ }
+
+ @Override
+ public long getLong() {
+ return 0;
+ }
+
+ @Override
+ public double getDouble() {
+ return 0;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/InstantiatedComponent.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/InstantiatedComponent.java
new file mode 100644
index 0000000..8d6d02d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/components/InstantiatedComponent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.components.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+
+/**
+ * A component using factory name and instantiate.
+ */
+@Component(name = "MyInstantiatedComponent")
+@Instantiate
+public class InstantiatedComponent {
+
+ // Do nothing.
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ComponentUsingContext.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ComponentUsingContext.java
new file mode 100644
index 0000000..25ea647
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ComponentUsingContext.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.components.context;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Property;
+import org.osgi.framework.BundleContext;
+
+/**
+ * A component using the @Context annotation
+ */
+@Component
+public class ComponentUsingContext {
+
+ @Context
+ private BundleContext field;
+
+ public ComponentUsingContext(@Property String property,
+ @Context(Context.Source.COMPONENT) BundleContext ctxt) {
+
+ }
+
+ @Context(Context.Source.INSTANCE)
+ public void setContext(BundleContext context) {
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/AbstractClass.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/AbstractClass.java
new file mode 100644
index 0000000..0a4132d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/AbstractClass.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.components.error;
+
+import org.apache.felix.ipojo.annotations.Requires;
+
+public abstract class AbstractClass {
+
+ @Requires
+ private Runnable run;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSub.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSub.java
new file mode 100644
index 0000000..d2ffcc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSub.java
@@ -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.felix.ipojo.runtime.core.test.components.event;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.event.Subscriber;
+import org.osgi.service.event.Event;
+
+
+@Component
+public class PubSub {
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p1", synchronous=true)
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher1;
+
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p2", synchronous=false, topics="foo,bar", dataKey="data")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher2;
+
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p3", synchronous=true, topics="bar")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher3;
+
+ @Subscriber(name="s1", dataKey="data")
+ public void receive1(Object foo) {
+ // Nothing
+ }
+
+ @Subscriber(name="s2", topics="foo,bar", filter="(foo=true)")
+ public void receive2(Event foo) {
+ // Nothing
+ }
+
+
+ @Subscriber(name="s3", topics= "foo", dataKey="data", dataType="java.lang.String")
+ public void receive3(String foo) {
+ // Nothing
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubDeprecated.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubDeprecated.java
new file mode 100644
index 0000000..0eb4fe3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubDeprecated.java
@@ -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.felix.ipojo.runtime.core.test.components.event;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.event.Subscriber;
+import org.osgi.service.event.Event;
+
+
+@Component
+public class PubSubDeprecated {
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p1", synchronous=true)
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher1;
+
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p2", synchronous=false, topics="foo,bar", data_key="data")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher2;
+
+ @org.apache.felix.ipojo.handlers.event.Publisher(name="p3", synchronous=true, topics="bar")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher3;
+
+ @Subscriber(name="s1", data_key="data")
+ public void receive1(Object foo) {
+ // Nothing
+ }
+
+ @Subscriber(name="s2", topics="foo,bar", filter="(foo=true)")
+ public void receive2(Event foo) {
+ // Nothing
+ }
+
+
+ @Subscriber(name="s3", topics= "foo", data_key="data", data_type="java.lang.String")
+ public void receive3(String foo) {
+ // Nothing
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubWithPublishes.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubWithPublishes.java
new file mode 100644
index 0000000..76749c1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/event/PubSubWithPublishes.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.components.event;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.event.Publishes;
+import org.apache.felix.ipojo.handlers.event.Subscriber;
+import org.osgi.service.event.Event;
+
+
+@Component
+public class PubSubWithPublishes {
+ @Publishes(name="p1", synchronous=true)
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher1;
+
+ @Publishes(name="p2", synchronous=false, topics="foo,bar", dataKey="data")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher2;
+
+ @Publishes(name="p3", synchronous=true, topics="bar")
+ org.apache.felix.ipojo.handlers.event.publisher.Publisher publisher3;
+
+ @Subscriber(name="s1", dataKey="data")
+ public void receive1(Object foo) {
+ // Nothing
+ }
+
+ @Subscriber(name="s2", topics="foo,bar", filter="(foo=true)")
+ public void receive2(Event foo) {
+ // Nothing
+ }
+
+
+ @Subscriber(name="s3", topics= "foo", dataKey="data", dataType="java.lang.String")
+ public void receive3(String foo) {
+ // Nothing
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/extender/Extender.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/extender/Extender.java
new file mode 100644
index 0000000..30ce4c6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/extender/Extender.java
@@ -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.runtime.core.test.components.extender;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.osgi.framework.Bundle;
+
+
+@Component
+@org.apache.felix.ipojo.extender.Extender(extension= "foo", onArrival="onArrival", onDeparture="onDeparture")
+public class Extender {
+
+ public void onArrival(Bundle bundle, String foo) {
+ // nothing
+ }
+
+ public void onDeparture(Bundle bundle) {
+ // nothing
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXDeprecated.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXDeprecated.java
new file mode 100644
index 0000000..f5be907
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXDeprecated.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.components.jmx;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.jmx.Config;
+import org.apache.felix.ipojo.handlers.jmx.Method;
+import org.apache.felix.ipojo.handlers.jmx.Property;
+
+@Component
+@Config(domain="my-domain", usesMOSGi=false)
+public class JMXDeprecated {
+
+ @Property(name="prop", notification=true, rights="w")
+ String m_foo;
+
+ @Method(description="set the foo prop")
+ public void setFoo(String mes) {
+ System.out.println("Set foo to " + mes);
+ m_foo = mes;
+ }
+
+ @Method(description="get the foo prop")
+ public String getFoo() {
+ return m_foo;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXSimple.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXSimple.java
new file mode 100644
index 0000000..a350797
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/jmx/JMXSimple.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.components.jmx;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handlers.jmx.Config;
+import org.apache.felix.ipojo.handlers.jmx.JMXMethod;
+import org.apache.felix.ipojo.handlers.jmx.JMXProperty;
+
+@Component
+@Config(domain="my-domain", usesMOSGi=false)
+public class JMXSimple {
+
+ @JMXProperty(name="prop", notification=true, rights="w")
+ String m_foo;
+
+ @JMXMethod(description="set the foo prop")
+ public void setFoo(String mes) {
+ System.out.println("Set foo to " + mes);
+ m_foo = mes;
+ }
+
+ @JMXMethod(description="get the foo prop")
+ public String getFoo() {
+ return m_foo;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/Temporal.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/Temporal.java
new file mode 100644
index 0000000..0825101
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/Temporal.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class Temporal {
+
+ @org.apache.felix.ipojo.handler.temporal.Temporal
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalCollection.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalCollection.java
new file mode 100644
index 0000000..d0cb5cd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalCollection.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.components.temporal;
+
+import java.util.Collection;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+
+@Component
+public class TemporalCollection {
+
+ @Requires(specification="org.apache.felix.ipojo.runtime.core.test.services.FooService")
+ private Collection fs1;
+
+ @Requires(specification="org.apache.felix.ipojo.runtime.core.test.services.FooService", timeout=300)
+ private Collection fs2;
+
+ @Requires(onTimeout="empty", specification="org.apache.felix.ipojo.runtime.core.test.services.FooService")
+ private Collection fs3;
+
+ @Requires(proxy=true, specification="org.apache.felix.ipojo.runtime.core.test.services.FooService")
+ private Collection fs4;
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalSimple.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalSimple.java
new file mode 100644
index 0000000..9e5f016
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalSimple.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalSimple {
+
+ @Requires
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithDI.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithDI.java
new file mode 100644
index 0000000..9fd4de5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithDI.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithDI {
+
+ @Requires(onTimeout="org.apache.felix.ipojo.runtime.core.test.components.ProvidesSimple")
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithEmptyArray.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithEmptyArray.java
new file mode 100644
index 0000000..7c90920
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithEmptyArray.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithEmptyArray {
+
+ @Requires(onTimeout="empty-array")
+ private FooService fs[];
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithFilter.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithFilter.java
new file mode 100644
index 0000000..3bce201
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithFilter.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithFilter {
+
+ @Requires(filter="(vendor=clement)")
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNull.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNull.java
new file mode 100644
index 0000000..fb566b6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNull.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithNull {
+
+ @Requires(onTimeout="null")
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNullable.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNullable.java
new file mode 100644
index 0000000..456e388
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithNullable.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithNullable {
+
+ @Requires(onTimeout="nullable")
+ private FooService fs;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithTimeout.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithTimeout.java
new file mode 100644
index 0000000..fab510f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/temporal/TemporalWithTimeout.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.components.temporal;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.handler.temporal.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+@Component
+public class TemporalWithTimeout {
+
+ @Requires(timeout=100)
+ private FooService fs;
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWIModification.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWIModification.java
new file mode 100644
index 0000000..18da796
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWIModification.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.components.whiteboard;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.osgi.framework.ServiceReference;
+
+@Component
+@org.apache.felix.ipojo.whiteboard.Wbp(filter="(foo=true)",
+ onArrival="onArrival",
+ onDeparture="onDeparture",
+ onModification="onModification")
+public class WhiteBoardWIModification {
+
+ public void onArrival(ServiceReference ref) {
+ // nothing
+ }
+
+ public void onDeparture(ServiceReference ref) {
+ // nothing
+ }
+
+ public void onModification(ServiceReference ref) {
+ // nothing
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWOModification.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWOModification.java
new file mode 100644
index 0000000..fd6e9b5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoardWOModification.java
@@ -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.runtime.core.test.components.whiteboard;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.osgi.framework.ServiceReference;
+
+@Component
+@org.apache.felix.ipojo.whiteboard.Wbp(filter="(foo=true)", onArrival="onArrival", onDeparture="onDeparture")
+public class WhiteBoardWOModification {
+
+ public void onArrival(ServiceReference ref) {
+ // nothing
+ }
+
+ public void onDeparture(ServiceReference ref) {
+ // nothing
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoards.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoards.java
new file mode 100644
index 0000000..b6c675c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/whiteboard/WhiteBoards.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.components.whiteboard;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.whiteboard.Whiteboards;
+import org.apache.felix.ipojo.whiteboard.Wbp;
+import org.osgi.framework.ServiceReference;
+
+@Component
+@Whiteboards(whiteboards={
+ @Wbp(filter="(foo=true)", onArrival="onArrival", onDeparture="onDeparture"),
+ @Wbp(filter="(foo=true)", onArrival="onArrival", onDeparture="onDeparture", onModification="onModification")
+ })
+public class WhiteBoards {
+
+ public void onArrival(ServiceReference ref) {
+ // nothing
+ }
+
+ public void onDeparture(ServiceReference ref) {
+ // nothing
+ }
+
+ public void onModification(ServiceReference ref) {
+ // nothing
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/BarService.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/BarService.java
new file mode 100644
index 0000000..9afc463
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..e4366ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ChildInterface.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ChildInterface.java
new file mode 100644
index 0000000..6a17326
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ChildInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test.services;
+
+public interface ChildInterface extends ParentInterface1, ParentInterface2 {
+
+ public void processChild();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..9b8e12b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface1.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface1.java
new file mode 100644
index 0000000..a266978
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface1.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test.services;
+
+public interface ParentInterface1 extends ParentParentInterface {
+
+ public void processParent1();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface2.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface2.java
new file mode 100644
index 0000000..fbf2ac4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentInterface2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test.services;
+
+public interface ParentInterface2 {
+
+ public void processParent2();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentParentInterface.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentParentInterface.java
new file mode 100644
index 0000000..f95d384
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/ParentParentInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test.services;
+
+public interface ParentParentInterface {
+
+ public void processParentParent();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/Common.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/Common.java
new file mode 100644
index 0000000..ea494fe
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/Common.java
@@ -0,0 +1,49 @@
+/*
+ * 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.test.annotations;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ow2.chameleon.testing.helpers.FestAssertOption.festAssertAsInProject;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[] {
+ eventadmin(),
+ festAssertAsInProject()
+ };
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.2.10"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin").versionAsInProject());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestAggregateDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestAggregateDependency.java
new file mode 100644
index 0000000..9172c4b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestAggregateDependency.java
@@ -0,0 +1,83 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class TestAggregateDependency extends Common {
+
+ private Element[] deps;
+
+ @Before
+ public void setUp() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components" +
+ ".AggregateDependency");
+ deps = meta.getElements("requires");
+ }
+
+ @Test
+ public void testCallbackBind() {
+ Element dep = getDependencyById(deps, "Bar");
+ String opt = dep.getAttribute("aggregate");
+ assertEquals("Check aggregate", "true", opt);
+ }
+
+ @Test
+ public void testCallbackUnbind() {
+ Element dep = getDependencyById(deps, "Baz");
+ String opt = dep.getAttribute("aggregate");
+ assertEquals("Check aggregate", "true", opt);
+ }
+
+ @Test
+ public void testBindOnly() {
+ Element dep = getDependencyById(deps, "bindonly");
+ String opt = dep.getAttribute("aggregate");
+ assertEquals("Check aggregate", "true", opt);
+ }
+
+ @Test
+ public void testUnbindOnly() {
+ Element dep = getDependencyById(deps, "unbindonly");
+ String opt = dep.getAttribute("aggregate");
+ assertEquals("Check aggregate", "true", opt);
+ }
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (int i = 0; i < deps.length; i++) {
+ String na = deps[i].getAttribute("id");
+ String field = deps[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestArchitecture.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestArchitecture.java
new file mode 100644
index 0000000..0eab45e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestArchitecture.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestArchitecture extends Common {
+
+ @Test
+ public void testArch() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components" +
+ ".Arch");
+ String arch = meta.getAttribute("architecture");
+ assertNotNull("Architecture exists ", arch);
+ assertEquals("Architecture value", "true", arch);
+ }
+
+ @Test
+ public void testNoArch() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components" +
+ ".NoArch");
+ String arch = meta.getAttribute("architecture");
+ assertNotNull("Architecture exists ", arch);
+ assertEquals("Architecture value", "false", arch);
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestContext.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestContext.java
new file mode 100644
index 0000000..40ca96f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestContext.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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Before;
+import org.junit.Test;
+import org.ow2.chameleon.testing.helpers.MetadataHelper;
+
+import static junit.framework.Assert.assertEquals;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks the parsing of the @Context annotation.
+ */
+public class TestContext extends Common {
+
+ private Element[] contexts;
+
+
+
+ @Before
+ public void setUp() {
+ Element meta = MetadataHelper.getMetadata(getTestBundle(),
+ "org.apache.felix.ipojo.runtime.core.test.components.context.ComponentUsingContext");
+ contexts = meta.getElements("context");
+ }
+
+ @Test
+ public void testFieldInjection() {
+ Element tested = null;
+ for (Element element : contexts) {
+ if (element.containsAttribute("field")) {
+ tested = element;
+ }
+ }
+ assertThat(tested).isNotNull();
+
+ assertThat(tested.getAttribute("field")).isEqualToIgnoringCase("field");
+ assertThat(tested.getAttribute("constructor-parameter")).isNull();
+ assertThat(tested.getAttribute("method")).isNull();
+ assertThat(tested.getAttribute("value")).isNull(); // Not set
+ }
+
+ @Test
+ public void testConstructorInjection() {
+ Element tested = null;
+ for (Element element : contexts) {
+ if (element.containsAttribute("constructor-parameter")) {
+ tested = element;
+ }
+ }
+ assertThat(tested).isNotNull();
+
+ assertThat(tested.getAttribute("field")).isNull();
+ assertThat(tested.getAttribute("method")).isNull();
+ // 0 : Property, 1 context
+ assertThat(tested.getAttribute("constructor-parameter")).isEqualToIgnoringCase("1");
+ assertThat(tested.getAttribute("value")).isEqualToIgnoringCase("COMPONENT");
+ }
+
+ @Test
+ public void testMethodInjection() {
+ Element tested = null;
+ for (Element element : contexts) {
+ if (element.containsAttribute("method")) {
+ tested = element;
+ }
+ }
+ assertThat(tested).isNotNull();
+
+ assertThat(tested.getAttribute("field")).isNull();
+ assertThat(tested.getAttribute("parameter-index")).isNull();
+ assertThat(tested.getAttribute("method")).isEqualToIgnoringCase("setContext");
+ assertThat(tested.getAttribute("value")).isEqualToIgnoringCase("INSTANCE");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestCustomAnnotations.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestCustomAnnotations.java
new file mode 100644
index 0000000..5cd3368
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestCustomAnnotations.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Checks the support of the custom annotation handlinig.
+ */
+public class TestCustomAnnotations extends Common {
+
+
+ @Test
+ public void testThatCustomAnnotationAreCorrectlyAdded() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.CustomAnnotationWithEnum");
+ Element[] ann = meta.getElements("IPOJOFoo", "foo.ipojo");
+ assertNotNull("Annotation exists ", ann);
+ }
+
+ @Test
+ public void testThatCustomAnnotationAreSupportingEnums() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.CustomAnnotationWithEnum");
+ Element[] ann = meta.getElements("IPOJOFoo", "foo.ipojo");
+ assertNotNull("Annotation exists ", ann);
+ Element element = ann[0];
+ // Simple value
+ assertEquals("RED", element.getAttribute("rgb"));
+ // Array (FELIX-3508).
+ assertEquals("{BLUE,RED}", element.getAttribute("colors"));
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependency.java
new file mode 100644
index 0000000..7a26f23
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependency.java
@@ -0,0 +1,187 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.*;
+
+public class TestDependency extends Common {
+
+
+ @Test
+ public void testDependencyDeclaration() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(),
+ "org.apache.felix.ipojo.runtime.core.test.components.Dependency");
+ Element[] deps = meta.getElements("requires");
+
+ // Check fs
+ Element dep = getDependencyById(deps, "fs");
+ String field = dep.getAttribute("field");
+ String id = dep.getAttribute("id");
+ String bind = getBind(dep);
+ String unbind = getUnbind(dep);
+ assertNotNull("Check fs field", field);
+ assertEquals("Check fs field", "fs", field);
+ assertNull("Check fs bind", bind);
+ assertNull("Check fs unbind", unbind);
+ assertNull("Check fs id", id);
+
+ // Check bar
+ dep = getDependencyById(deps, "Bar");
+ field = dep.getAttribute("field");
+ id = dep.getAttribute("id");
+ bind = getBind(dep);
+ unbind = getUnbind(dep);
+ assertNull("Check bar field", field);
+ assertEquals("Check bar bind", "bindBar", bind);
+ assertEquals("Check bar unbind", "unbindBar", unbind);
+ assertEquals("Check bar id", "Bar", id);
+
+ // Check baz
+ dep = getDependencyById(deps, "Baz");
+ field = dep.getAttribute("field");
+ id = dep.getAttribute("id");
+ bind = getBind(dep);
+ unbind = getUnbind(dep);
+ assertNull("Check baz field", field);
+ assertEquals("Check baz bind", "bindBaz", bind);
+ assertEquals("Check baz unbind", "unbindBaz", unbind);
+ assertEquals("Check baz id", "Baz", id);
+
+ // Check fs2
+ dep = getDependencyById(deps, "fs2");
+ field = dep.getAttribute("field");
+ id = dep.getAttribute("id");
+ bind = getBind(dep);
+ unbind = getUnbind(dep);
+ assertNotNull("Check fs2 field", field);
+ assertEquals("Check fs2 field", "fs2", field);
+ assertEquals("Check fs2 bind", "bindFS2", bind);
+ assertEquals("Check fs2 unbind", "unbindFS2", unbind);
+
+ // Check fs2inv
+ dep = getDependencyById(deps, "fs2inv");
+ field = dep.getAttribute("field");
+ id = dep.getAttribute("id");
+ bind = getBind(dep);
+ unbind = getUnbind(dep);
+ assertNotNull("Check fs2inv field", field);
+ assertEquals("Check fs2 field", "fs2inv", field);
+ assertEquals("Check fs2 bind", "bindFS2Inv", bind);
+ assertEquals("Check fs2 unbind", "unbindFS2Inv", unbind);
+ assertEquals("Check fs2 id", "inv", id);
+
+ // Check mod
+ dep = getDependencyById(deps, "mod");
+ id = dep.getAttribute("id");
+ bind = getBind(dep);
+ unbind = getUnbind(dep);
+ String mod = getModified(dep);
+ assertEquals("Check mod bind", "bindMod", bind);
+ assertEquals("Check mod unbind", "unbindMod", unbind);
+ assertEquals("Check mod modified", "modifiedMod", mod);
+ assertEquals("Check mod id", "mod", id);
+
+ // Check not proxied
+ dep = getDependencyById(deps, "notproxied");
+ assertEquals("Check not proxied", "false", dep.getAttribute("proxy"));
+ }
+
+ /**
+ * Reproduce https://issues.apache.org/jira/browse/FELIX-4380.
+ */
+ @Test
+ public void testDependencyUsingSpecification() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.DependencyUsingSpecification");
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(),
+ instance.getInstanceName());
+
+ assertNotNull(ref);
+
+ CheckService svc = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertFalse(svc.check());
+
+ // The following instantiation exposes the BarService required by instance.
+ ComponentInstance bar = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.ProvidesSimple");
+
+ assertTrue(svc.check());
+
+ bar.dispose();
+ assertFalse(svc.check());
+ }
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (int i = 0; i < deps.length; i++) {
+ String na = deps[i].getAttribute("id");
+ String field = deps[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+ private String getBind(Element dep) {
+ Element[] elem = dep.getElements("callback");
+ for (int i = 0; elem != null && i < elem.length; i++) {
+ if (elem[i].getAttribute("type").equalsIgnoreCase("bind")) {
+ return elem[i].getAttribute("method");
+ }
+ }
+ return null;
+ }
+
+ private String getUnbind(Element dep) {
+ Element[] elem = dep.getElements("callback");
+ for (int i = 0; elem != null && i < elem.length; i++) {
+ if (elem[i].getAttribute("type").equalsIgnoreCase("unbind")) {
+ return elem[i].getAttribute("method");
+ }
+ }
+ return null;
+ }
+
+ private String getModified(Element dep) {
+ Element[] elem = dep.getElements("callback");
+ for (int i = 0; elem != null && i < elem.length; i++) {
+ if (elem[i].getAttribute("type").equalsIgnoreCase("modified")) {
+ return elem[i].getAttribute("method");
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependencyPolicy.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependencyPolicy.java
new file mode 100644
index 0000000..e726a3f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestDependencyPolicy.java
@@ -0,0 +1,104 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class TestDependencyPolicy extends Common {
+
+ private Element[] deps;
+
+ @Before
+ public void setUp() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.PolicyDependency");
+ deps = meta.getElements("requires");
+ }
+
+ @Test
+ public void testField() {
+ Element dep = getDependencyById(deps, "fs");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+ @Test
+ public void testFieldDPpolicy() {
+ Element dep = getDependencyById(deps, "fs2");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "dynamic-priority", opt);
+ }
+
+ @Test
+ public void testCallbackBind() {
+ Element dep = getDependencyById(deps, "Bar");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+ @Test
+ public void testCallbackUnbind() {
+ Element dep = getDependencyById(deps, "Baz");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+ @Test
+ public void testBoth() {
+ Element dep = getDependencyById(deps, "inv");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+ @Test
+ public void testBindOnly() {
+ Element dep = getDependencyById(deps, "bindonly");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+ @Test
+ public void testUnbindOnly() {
+ Element dep = getDependencyById(deps, "unbindonly");
+ String opt = dep.getAttribute("policy");
+ assertEquals("Check policy", "static", opt);
+ }
+
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (Element dep : deps) {
+ String na = dep.getAttribute("id");
+ String field = dep.getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return dep;
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return dep;
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestEventAdmin.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestEventAdmin.java
new file mode 100644
index 0000000..acad7e8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestEventAdmin.java
@@ -0,0 +1,287 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TestEventAdmin extends Common {
+ String type = "org.apache.felix.ipojo.runtime.core.test.components.event.PubSub";
+ String deprecated = "org.apache.felix.ipojo.runtime.core.test.components.event.PubSubDeprecated";
+ String publishes = "org.apache.felix.ipojo.runtime.core.test.components.event.PubSubWithPublishes";
+
+ String namespace = "org.apache.felix.ipojo.handlers.event";
+
+ Element component;
+ Element componentDeprecated;
+ Element componentWithPublishes;
+
+ @Before
+ public void setUp() {
+ component = ipojoHelper.getMetadata(getTestBundle(), type);
+ componentDeprecated = ipojoHelper.getMetadata(getTestBundle(), deprecated);
+ componentWithPublishes = ipojoHelper.getMetadata(getTestBundle(), publishes);
+ assertNotNull("Check component", component);
+ assertNotNull("Check deprecated", componentDeprecated);
+ assertNotNull("Check publishes", componentWithPublishes);
+
+ }
+
+ @After
+ public void tearDown() {
+ component = null;
+ componentDeprecated = null;
+ componentWithPublishes = null;
+ }
+
+ @Test
+ public void testP1() {
+ //P1, synchronous
+ Element elem = getElementByName("p1");
+ checkPublisher(elem);
+ assertNull("Check topics", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher1", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testP1WithPublishes() {
+ //P1, synchronous
+ Element elem = getPublishesByName("p1");
+ checkPublishes(elem);
+ assertNull("Check topics", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher1", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testP1Deprecated() {
+ //P1, synchronous
+ Element elem = getDeprecatedElementByName("p1");
+ checkPublisher(elem);
+ assertNull("Check topics", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher1", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("data_key"));
+ }
+
+ @Test
+ public void testP2() {
+ //name="p2", synchronous=false, topics="foo,bar", data_key="data"
+ Element elem = getElementByName("p2");
+ checkPublisher(elem);
+ assertEquals("Check topics (" + elem.getAttribute("topics") + ")", "foo,bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "false", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher2", elem.getAttribute("field"));
+ assertEquals("Check data_key", "data", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testP2WithPublishes() {
+ //name="p2", synchronous=false, topics="foo,bar", data_key="data"
+ Element elem = getPublishesByName("p2");
+ checkPublishes(elem);
+ assertEquals("Check topics (" + elem.getAttribute("topics") + ")", "foo,bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "false", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher2", elem.getAttribute("field"));
+ assertEquals("Check data_key", "data", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testP2Deprecated() {
+ //name="p2", synchronous=false, topics="foo,bar", data_key="data"
+ Element elem = getDeprecatedElementByName("p2");
+ checkPublisher(elem);
+ assertEquals("Check topics (" + elem.getAttribute("topics") + ")", "foo,bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "false", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher2", elem.getAttribute("field"));
+ assertEquals("Check data_key", "data", elem.getAttribute("data_key"));
+ }
+
+ @Test
+ public void testP3() {
+ //name="p3", synchronous=true, topics="bar"
+ Element elem = getElementByName("p3");
+ checkPublisher(elem);
+ assertEquals("Check topics", "bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher3", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testWithPublishesP3() {
+ //name="p3", synchronous=true, topics="bar"
+ Element elem = getPublishesByName("p3");
+ checkPublishes(elem);
+ assertEquals("Check topics", "bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher3", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("dataKey"));
+ }
+
+ @Test
+ public void testP3Deprecated() {
+ //name="p3", synchronous=true, topics="bar"
+ Element elem = getDeprecatedElementByName("p3");
+ checkPublisher(elem);
+ assertEquals("Check topics", "bar", elem.getAttribute("topics"));
+ assertEquals("Check synchronous", "true", elem.getAttribute("synchronous"));
+ assertEquals("Check field", "publisher3", elem.getAttribute("field"));
+ assertNull("Check data_key", elem.getAttribute("data_key"));
+ }
+
+ @Test
+ public void testS1() {
+ //name="s1", data_key="data"
+ Element elem = getElementByName("s1");
+ checkSubscriber(elem);
+ assertNull("Check topics", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive1", elem.getAttribute("method"));
+ assertEquals("Check data_key", "data", elem.getAttribute("dataKey"));
+ assertNull("Check data_type", elem.getAttribute("dataType"));
+ assertNull("Check filter", elem.getAttribute("filter"));
+ }
+
+ @Test
+ public void testS1Deprecated() {
+ //name="s1", data_key="data"
+ Element elem = getDeprecatedElementByName("s1");
+ checkSubscriber(elem);
+ assertNull("Check topics", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive1", elem.getAttribute("method"));
+ assertEquals("Check data_key", "data", elem.getAttribute("data_key"));
+ assertNull("Check data_type", elem.getAttribute("data_type"));
+ assertNull("Check filter", elem.getAttribute("filter"));
+ }
+
+ @Test
+ public void testS2() {
+ //name="s2", topics="foo,bar", filter="(foo=true)"
+ Element elem = getElementByName("s2");
+ checkSubscriber(elem);
+ assertEquals("Check topics", "foo,bar", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive2", elem.getAttribute("method"));
+ assertNull("Check data_key", elem.getAttribute("dataKey"));
+ assertNull("Check data_type", elem.getAttribute("dataType"));
+ assertEquals("Check filter", "(foo=true)", elem.getAttribute("filter"));
+ }
+
+ @Test
+ public void testS2Deprecated() {
+ //name="s2", topics="foo,bar", filter="(foo=true)"
+ Element elem = getDeprecatedElementByName("s2");
+ checkSubscriber(elem);
+ assertEquals("Check topics", "foo,bar", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive2", elem.getAttribute("method"));
+ assertNull("Check data_key", elem.getAttribute("data_key"));
+ assertNull("Check data_type", elem.getAttribute("data_type"));
+ assertEquals("Check filter", "(foo=true)", elem.getAttribute("filter"));
+ }
+
+ @Test
+ public void testS3() {
+ //name="s3", topics="foo", data_key="data", data_type="java.lang.String"
+ Element elem = getElementByName("s3");
+ checkSubscriber(elem);
+ assertEquals("Check topics", "foo", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive3", elem.getAttribute("method"));
+ assertEquals("Check data_key", "data", elem.getAttribute("dataKey"));
+ assertEquals("Check data_type", "java.lang.String", elem.getAttribute("dataType"));
+ assertNull("Check filter", elem.getAttribute("filter"));
+ }
+
+ @Test
+ public void testS3Deprecated() {
+ //name="s3", topics="foo", data_key="data", data_type="java.lang.String"
+ Element elem = getDeprecatedElementByName("s3");
+ checkSubscriber(elem);
+ assertEquals("Check topics", "foo", elem.getAttribute("topics"));
+ assertEquals("Check method", "receive3", elem.getAttribute("method"));
+ assertEquals("Check data_key", "data", elem.getAttribute("data_key"));
+ assertEquals("Check data_type", "java.lang.String", elem.getAttribute("data_type"));
+ assertNull("Check filter", elem.getAttribute("filter"));
+ }
+
+
+ public Element getElementByName(String name) {
+ Element[] elems = component.getElements();
+ for (int i = 0; i < elems.length; i++) {
+ if (elems[i].containsAttribute("name") && elems[i].getAttribute("name").equals(name)) {
+ return elems[i];
+ }
+ }
+ return null;
+ }
+
+ public Element getPublishesByName(String name) {
+ Element[] elems = componentWithPublishes.getElements();
+ for (int i = 0; i < elems.length; i++) {
+ if (elems[i].containsAttribute("name") && elems[i].getAttribute("name").equals(name)) {
+ return elems[i];
+ }
+ }
+ return null;
+ }
+
+ public Element getDeprecatedElementByName(String name) {
+ Element[] elems = componentDeprecated.getElements();
+ for (int i = 0; i < elems.length; i++) {
+ if (elems[i].containsAttribute("name") && elems[i].getAttribute("name").equals(name)) {
+ return elems[i];
+ }
+ }
+ return null;
+ }
+
+ public void checkSubscriber(Element elem) {
+ assertNotNull("Can't check subscriber : null element", elem);
+ String ns = elem.getNameSpace();
+ String nm = elem.getName();
+ assertEquals("Elem is not a subscriber : bad namespace", namespace, ns);
+ assertEquals("Elem is not a subscriber : bad name", "subscriber", nm);
+
+ }
+
+ public void checkPublisher(Element elem) {
+ assertNotNull("Can't check publisher : null element", elem);
+ String ns = elem.getNameSpace();
+ String nm = elem.getName();
+ assertEquals("Elem is not a publisher : bad namespace", namespace, ns);
+ assertEquals("Elem is not a publisher : bad name", "publisher", nm);
+ }
+
+ public void checkPublishes(Element elem) {
+ assertNotNull("Can't check publisher : null element", elem);
+ String ns = elem.getNameSpace();
+ String nm = elem.getName();
+ assertEquals("Elem is not a publisher : bad namespace", namespace, ns);
+ assertEquals("Elem is not a publisher : bad name", "publishes", nm);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestExtender.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestExtender.java
new file mode 100644
index 0000000..62ca1b1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestExtender.java
@@ -0,0 +1,49 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestExtender extends Common {
+
+ String type = "org.apache.felix.ipojo.runtime.core.test.components.extender.Extender";
+ String namespace = "org.apache.felix.ipojo.extender";
+
+
+ @Test
+ public void testMetadata() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), type);
+ assertNotNull("Check meta", meta);
+ Element[] ext = meta.getElements("extender", namespace);
+ assertEquals("Check size", 1, ext.length);
+ String extension = ext[0].getAttribute("extension");
+ String onArr = ext[0].getAttribute("onArrival");
+ String onDep = ext[0].getAttribute("onDeparture");
+
+ assertEquals("Check extension", "foo", extension);
+ assertEquals("Check onArrival", "onArrival", onArr);
+ assertEquals("Check onDeparture", "onDeparture", onDep);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFactory.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFactory.java
new file mode 100644
index 0000000..c003138
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFactory.java
@@ -0,0 +1,98 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TestFactory extends Common {
+
+
+ @Test
+ public void testArchDeprecated() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FactoryDeprecated");
+ String fact = meta.getAttribute("public");
+ String name = meta.getAttribute("name");
+ assertNotNull("Factory exists ", fact);
+ assertEquals("Factory value", "true", fact);
+ assertNotNull("Name exists ", name);
+ assertEquals("Name value", "org.apache.felix.ipojo.runtime.core.test.components.FactoryDeprecated", name);
+ }
+
+ @Test
+ public void testArch() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Factory");
+ String fact = meta.getAttribute("public");
+ String name = meta.getAttribute("name");
+ assertNotNull("Factory exists ", fact);
+ assertEquals("Factory value", "true", fact);
+ assertNotNull("Name exists ", name);
+ assertEquals("Name value", "factory", name);
+ }
+
+ @Test
+ public void testNoArch() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.NoFactory");
+ String fact = meta.getAttribute("public");
+ String name = meta.getAttribute("name");
+ assertNotNull("Factory exists ", fact);
+ assertEquals("Factory value", "false", fact);
+ assertNotNull("Name exists ", name);
+ assertEquals("Name value", "nofactory", name);
+ }
+
+ @Test
+ public void testFactoryMethod() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FactoryMethod");
+ String method = meta.getAttribute("factory-method");
+ assertNotNull("Method exists ", method);
+ assertEquals("Method value", "create", method);
+ }
+
+ @Test
+ public void testFactoryMethodDeprecated() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FactoryMethodDeprecated");
+ String method = meta.getAttribute("factory-method");
+ assertNotNull("Method exists ", method);
+ assertEquals("Method value", "create", method);
+ }
+
+ @Test
+ public void testVersion() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ComponentTypeVersion");
+ String version = meta.getAttribute("version");
+ assertNotNull("Version exist", version);
+ assertEquals("Version value", "1.0.0", version);
+ }
+
+ @Test
+ public void testNoVersion() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FactoryMethod");
+ String version = meta.getAttribute("version");
+ assertNull("No Version", version);
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFilteredDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFilteredDependency.java
new file mode 100644
index 0000000..27aee56
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestFilteredDependency.java
@@ -0,0 +1,132 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+public class TestFilteredDependency extends Common {
+
+ private Element[] deps;
+ private Element[] froms;
+
+
+ @Before
+ public void setUp() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FilteredDependency");
+ deps = meta.getElements("requires");
+
+ Element meta2 = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.FromDependency");
+ froms = meta2.getElements("requires");
+ }
+
+ @Test
+ public void testField() {
+ Element dep = getDependencyById(deps, "fs");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testCallbackBind() {
+ Element dep = getDependencyById(deps, "Bar");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testCallbackUnbind() {
+ Element dep = getDependencyById(deps, "Baz");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testBoth() {
+ Element dep = getDependencyById(deps, "inv");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testBindOnly() {
+ Element dep = getDependencyById(deps, "bindonly");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testUnbindOnly() {
+ Element dep = getDependencyById(deps, "unbindonly");
+ String opt = dep.getAttribute("filter");
+ assertEquals("Check filter", "(foo=bar)", opt);
+ }
+
+ @Test
+ public void testFromField() {
+ Element dep = getDependencyById(froms, "fs");
+ String from = dep.getAttribute("from");
+ assertEquals("Check from", "X", from);
+ }
+
+ @Test
+ public void testFromBind() {
+ Element dep = getDependencyById(froms, "fs2");
+ String from = dep.getAttribute("from");
+ assertEquals("Check from", "X", from);
+ }
+
+ @Test
+ public void testFromUnbind() {
+ Element dep = getDependencyById(froms, "inv");
+ String from = dep.getAttribute("from");
+ assertEquals("Check from", "X", from);
+ }
+
+ @Test
+ public void testNoFrom() {
+ Element dep = getDependencyById(froms, "Bar");
+ String from = dep.getAttribute("from");
+ assertNull("Check from", from);
+ }
+
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (int i = 0; i < deps.length; i++) {
+ String na = deps[i].getAttribute("id");
+ String field = deps[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiate.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiate.java
new file mode 100644
index 0000000..aed4e25
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiate.java
@@ -0,0 +1,128 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TestInstantiate extends Common {
+
+
+ @Test
+ public void testInstantiateSimple() {
+ Element[] meta = getInstanceMetadata(getTestBundle(),
+ "org.apache.felix.ipojo.runtime.core.test" +
+ ".components" +
+ ".InstantiateSimple");
+ assertNotNull(meta);
+ assertEquals(1, meta.length);
+ assertNull(meta[0].getAttribute("name"));
+ assertEquals(0, meta[0].getElements().length);
+ }
+
+ @Test
+ public void testInstantiateWithName() {
+ // Check instance tag
+ Element[] meta = getInstanceMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components" +
+ ".InstantiateWithName");
+ assertNotNull(meta);
+ assertEquals(1, meta.length);
+ assertNotNull(meta[0].getAttribute("name"));
+ assertEquals("myInstantiatedInstance", meta[0].getAttribute("name"));
+ assertEquals(0, meta[0].getElements().length);
+ }
+
+ @Test
+ public void testInstanceCreation() throws InvalidSyntaxException {
+ String in = "org.apache.felix.ipojo.runtime.core.test.components.InstantiateSimple-0";
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(org.apache.felix.ipojo.architecture.Architecture.class.getName(),
+ in);
+ assertNotNull(ref);
+ }
+
+ @Test
+ public void testInstanceCreationWithName() {
+ String in = "myInstantiatedInstance";
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(org.apache.felix.ipojo.architecture.Architecture.class.getName(),
+ in);
+ assertNotNull(ref);
+ }
+
+ /**
+ * Returns the instance metadatas of the component with the given name,
+ * defined in the given bundle.
+ *
+ * @param bundle the bundle from which the component is defined.
+ * @param component the name of the defined component.
+ * @return the list of instance metadata of the component with the given name,
+ * defined in the given bundle, or {@code null} if not found.
+ */
+ public static Element[] getInstanceMetadata(Bundle bundle, String component) {
+
+ // Retrieves the component description from the bundle's manifest.
+ String elem = (String) bundle.getHeaders().get("iPOJO-Components");
+ if (elem == null) {
+ throw new IllegalArgumentException(
+ "Cannot find iPOJO-Components descriptor in the specified bundle ("
+ + bundle.getSymbolicName()
+ + "). Not an iPOJO bundle.");
+ }
+
+ // Parses the retrieved description and find the component with the
+ // given name.
+ List<Element> list = new ArrayList<Element>();
+ try {
+ Element element = ManifestMetadataParser.parseHeaderMetadata(elem);
+ Element[] childs = element.getElements("instance");
+ for (int i = 0; i < childs.length; i++) {
+ String name = childs[i].getAttribute("component");
+ if (name != null && name.equalsIgnoreCase(component)) {
+ list.add(childs[i]);
+ }
+ }
+
+ if (list.isEmpty()) {
+ // Component not found...
+ return null;
+ } else {
+ return (Element[]) list.toArray(new Element[list.size()]);
+ }
+
+ } catch (ParseException e) {
+ throw new IllegalStateException(
+ "Cannot parse the components from specified bundle ("
+ + bundle.getSymbolicName() + "): " + e.getMessage());
+ }
+ }
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiatedComponent.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiatedComponent.java
new file mode 100644
index 0000000..f0b4fad
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestInstantiatedComponent.java
@@ -0,0 +1,45 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+/**
+ * Checks that a component setting a name and using the @Instantiate annotation creates the instance correctly.
+ * It reproduce {@link https://issues.apache.org/jira/browse/FELIX-4052}
+ */
+public class TestInstantiatedComponent extends Common {
+
+ @Test
+ public void testInstanceCreation() {
+ // This is the expected name.
+ Architecture architecture = osgiHelper.getServiceObject(Architecture.class,
+ "(architecture.instance=MyInstantiatedComponent-0)");
+
+ assertNotNull(architecture);
+ assertEquals(ComponentInstance.VALID, architecture.getInstanceDescription().getState());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestJMX.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestJMX.java
new file mode 100644
index 0000000..074a600
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestJMX.java
@@ -0,0 +1,85 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestJMX extends Common {
+
+
+ @Test
+ public void testDeprecated() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.jmx.JMXDeprecated");
+ /*
+ * org.apache.felix.ipojo.handlers.jmx:config domain="my-domain" usesmosgi="false"
+ org.apache.felix.ipojo.handlers.jmx:property field="m_foo" name="prop" rights="w" notification="true"
+ org.apache.felix.ipojo.handlers.jmx:method description="get the foo prop" method="getFoo"
+ org.apache.felix.ipojo.handlers.jmx:method description="set the foo prop" method="setFoo"
+ */
+
+ Element[] ele = meta.getElements("config", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("ele not null", ele);
+ assertEquals("Ele size", 1, ele.length);
+ String domain = ele[0].getAttribute("domain");
+ String mosgi = ele[0].getAttribute("usesmosgi");
+ assertEquals("domain", "my-domain", domain);
+ assertEquals("mosgi", "false", mosgi);
+
+ Element[] props = ele[0].getElements("property", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("props not null", props);
+ assertEquals("props size", 1, props.length);
+
+ Element[] methods = ele[0].getElements("method", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("methods not null", methods);
+ assertEquals("methods size", 2, methods.length);
+ }
+
+ @Test
+ public void test() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.jmx.JMXSimple");
+ /*
+ * org.apache.felix.ipojo.handlers.jmx:config domain="my-domain" usesmosgi="false"
+ org.apache.felix.ipojo.handlers.jmx:property field="m_foo" name="prop" rights="w" notification="true"
+ org.apache.felix.ipojo.handlers.jmx:method description="get the foo prop" method="getFoo"
+ org.apache.felix.ipojo.handlers.jmx:method description="set the foo prop" method="setFoo"
+ */
+
+ Element[] ele = meta.getElements("config", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("ele not null", ele);
+ assertEquals("Ele size", 1, ele.length);
+ String domain = ele[0].getAttribute("domain");
+ String mosgi = ele[0].getAttribute("usesmosgi");
+ assertEquals("domain", "my-domain", domain);
+ assertEquals("mosgi", "false", mosgi);
+
+ Element[] props = ele[0].getElements("JMXProperty", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("props not null", props);
+ assertEquals("props size", 1, props.length);
+
+ Element[] methods = ele[0].getElements("JMXMethod", "org.apache.felix.ipojo.handlers.jmx");
+ assertNotNull("methods not null", methods);
+ assertEquals("methods size", 2, methods.length);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleCallbacks.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleCallbacks.java
new file mode 100644
index 0000000..458e708
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleCallbacks.java
@@ -0,0 +1,74 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestLifecycleCallbacks extends Common {
+
+
+ @Test
+ public void testCallbacks() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Lifecycle");
+ Element[] cbs = meta.getElements("callback");
+ assertNotNull("Callbacks exists ", cbs);
+ assertEquals("Callbacks count ", 2, cbs.length);
+
+ Element elem = getCallbackByMethodName(cbs, "start");
+ assertEquals("Check start method", "start", elem.getAttribute("method"));
+ assertEquals("Check start transition", "validate", elem.getAttribute("transition"));
+
+ elem = getCallbackByMethodName(cbs, "stop");
+ assertEquals("Check stop method", "stop", elem.getAttribute("method"));
+ assertEquals("Check stop transition", "invalidate", elem.getAttribute("transition"));
+ }
+
+ @Test
+ public void testImmediate() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Immediate");
+ assertNotNull("Immediate attribute", meta.getAttribute("immediate"));
+ assertEquals("Immediate attribute value", "true", meta.getAttribute("immediate"));
+ }
+
+ @Test
+ public void testNoImmediate() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.NoImmediate");
+ assertNotNull("Immediate attribute", meta.getAttribute("immediate"));
+ assertEquals("Immediate attribute value", "false", meta.getAttribute("immediate"));
+ }
+
+ private Element getCallbackByMethodName(Element[] cbs, String method) {
+ for (int i = 0; i < cbs.length; i++) {
+ String met = cbs[i].getAttribute("method");
+ if (met != null && met.equalsIgnoreCase(method)) {
+ return cbs[i];
+ }
+ }
+ fail("Cannot found the callback with the method " + method);
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleController.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleController.java
new file mode 100644
index 0000000..928ecf4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestLifecycleController.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestLifecycleController extends Common {
+
+ @Test
+ public void testLFC() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Lifecycle");
+ Element[] ctrls = meta.getElements("controller");
+ assertNotNull("Controller exists ", ctrls);
+ Element ctrl = ctrls[0];
+ assertNotNull("Field", ctrl.getAttribute("field"));
+ assertEquals("Field", "lfc", ctrl.getAttribute("field"));
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestOptionalDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestOptionalDependency.java
new file mode 100644
index 0000000..0a58108
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestOptionalDependency.java
@@ -0,0 +1,136 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.test.components.ProvidesSimple;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestOptionalDependency extends Common {
+
+ private Element[] deps;
+
+ @Before
+ public void setUp() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.OptionalDependency");
+ deps = meta.getElements("requires");
+ }
+
+ @Test
+ public void testField() {
+ Element dep = getDependencyById(deps, "fs");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testFieldNoOptional() {
+ Element dep = getDependencyById(deps, "fs2");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "false", opt);
+ }
+
+ @Test
+ public void testCallbackBind() {
+ Element dep = getDependencyById(deps, "Bar");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testCallbackUnbind() {
+ Element dep = getDependencyById(deps, "Baz");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testBoth() {
+ Element dep = getDependencyById(deps, "inv");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testBindOnly() {
+ Element dep = getDependencyById(deps, "bindonly");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testUnbindOnly() {
+ Element dep = getDependencyById(deps, "unbindonly");
+ String opt = dep.getAttribute("optional");
+ assertEquals("Check optionality", "true", opt);
+ }
+
+ @Test
+ public void testNullable() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.NullableDependency");
+ Element[] deps = meta.getElements("requires");
+ Element fs = getDependencyById(deps, "fs");
+ String nullable = fs.getAttribute("nullable");
+ assertNotNull("Check nullable", nullable);
+ assertEquals("Check nullable value", "true", nullable);
+ }
+
+ @Test
+ public void testNoNullable() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.NullableDependency");
+ Element[] deps = meta.getElements("requires");
+ Element fs = getDependencyById(deps, "fs2");
+ String nullable = fs.getAttribute("nullable");
+ assertNotNull("Check nullable", nullable);
+ assertEquals("Check nullable value", "false", nullable);
+ }
+
+ @Test
+ public void testDefaultImplementation() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.DefaultImplementationDependency");
+ Element[] deps = meta.getElements("requires");
+ Element fs = getDependencyById(deps, "fs");
+ String di = fs.getAttribute("default-implementation");
+ assertNotNull("Check DI", di);
+ assertEquals("Check DI value", "org.apache.felix.ipojo.runtime.core.test.components.ProvidesSimple", di);
+ }
+
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (int i = 0; i < deps.length; i++) {
+ String na = deps[i].getAttribute("id");
+ String field = deps[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestProperties.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestProperties.java
new file mode 100644
index 0000000..3f54706
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestProperties.java
@@ -0,0 +1,189 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.*;
+
+public class TestProperties extends Common {
+
+ @Test
+ public void testProperties() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Properties");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ Element[] props = prov.getElements("property");
+ assertEquals("Number of properties", props.length, 5);
+ //Foo
+ Element foo = getPropertyByName(props, "foo");
+ assertEquals("Check foo field", "m_foo", foo.getAttribute("field"));
+ assertEquals("Check foo name", "foo", foo.getAttribute("name"));
+ //Bar
+ Element bar = getPropertyByName(props, "bar");
+ assertEquals("Check bar field", "bar", bar.getAttribute("field"));
+ assertEquals("Check bar value", "4", bar.getAttribute("value"));
+ //Boo
+ Element boo = getPropertyByName(props, "boo");
+ assertEquals("Check boo field", "boo", boo.getAttribute("field"));
+ assertEquals("Check boo method", "setboo", boo.getAttribute("method"));
+ //Baa
+ Element baa = getPropertyByName(props, "baa");
+ assertEquals("Check baa field", "m_baa", baa.getAttribute("field"));
+ assertEquals("Check baa name", "baa", baa.getAttribute("name"));
+ assertEquals("Check baa method", "setbaa", baa.getAttribute("method"));
+ assertEquals("Check mandatory", "true", baa.getAttribute("mandatory"));
+
+
+ //Bar
+ Element baz = getPropertyByName(props, "baz");
+ assertEquals("Check baz method", "setbaz", baz.getAttribute("method"));
+ assertEquals("Check baz name", "baz", baz.getAttribute("name"));
+ }
+
+ @Test
+ public void testAbsentPropagation() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Properties");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("propagation");
+ assertNull("Propagation", att);
+ }
+
+ @Test
+ public void testPropagation() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Propagation");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("propagation");
+ assertNotNull("Propagation", att);
+ assertEquals("Propagation value", "true", att);
+ }
+
+ @Test
+ public void testNoPropagation() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.NoPropagation");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("propagation");
+ assertNotNull("Propagation", att);
+ assertEquals("Propagation value", "false", att);
+ }
+
+ @Test
+ public void testPID() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ManagedServicePID");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNotNull("PID", att);
+ assertEquals("PID Value", "MyPID", att);
+ }
+
+ @Test
+ public void testAbsentPID() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.Properties");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNull("PID", att);
+ }
+
+ @Test
+ public void testPropagationAndPID() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.PropagationandPID");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNotNull("PID", att);
+ assertEquals("PID Value", "MyPID", att);
+ att = prov.getAttribute("propagation");
+ assertNotNull("Propagation", att);
+ assertEquals("Propagation value", "true", att);
+ }
+
+ @Test
+ public void testPIDAndPropagation() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.PIDandPropagation");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNotNull("PID", att);
+ assertEquals("PID Value", "MyPID", att);
+ att = prov.getAttribute("propagation");
+ assertNotNull("Propagation", att);
+ assertEquals("Propagation value", "true", att);
+ }
+
+ @Test
+ public void testUpdatedAndPID() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.UpdatedWithManagedService");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNotNull("PID", att);
+ assertEquals("PID Value", "MyPID", att);
+
+ att = prov.getAttribute("updated");
+ assertNotNull("att", att);
+ assertEquals("Updated Value", "after", att);
+ }
+
+ @Test
+ public void testUpdatedAndProperties() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.UpdatedWithProperties");
+ Element[] provs = meta.getElements("properties");
+ assertNotNull("Properties exists ", provs);
+ Element prov = provs[0];
+ String att = prov.getAttribute("pid");
+ assertNull("PID", att);
+
+ att = prov.getAttribute("updated");
+ assertNotNull("att", att);
+ assertEquals("Updated Value", "after", att);
+ }
+
+ private Element getPropertyByName(Element[] props, String name) {
+ for (int i = 0; i < props.length; i++) {
+ String na = props[i].getAttribute("name");
+ String field = props[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return props[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return props[i];
+ }
+ }
+ fail("Property " + name + " not found");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestRankedDependency.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestRankedDependency.java
new file mode 100644
index 0000000..b1fa4c7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestRankedDependency.java
@@ -0,0 +1,98 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.test.components.MyComparator;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+public class TestRankedDependency extends Common {
+
+ private Element[] deps;
+
+ @Before
+ public void setUp() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.RankedDependency");
+ deps = meta.getElements("requires");
+ }
+
+ @Test
+ public void testField() {
+ Element dep = getDependencyById(deps, "fs");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+ @Test
+ public void testCallbackBind() {
+ Element dep = getDependencyById(deps, "Bar");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+ @Test
+ public void testCallbackUnbind() {
+ Element dep = getDependencyById(deps, "Baz");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+ @Test
+ public void testBoth() {
+ Element dep = getDependencyById(deps, "inv");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+ @Test
+ public void testBindOnly() {
+ Element dep = getDependencyById(deps, "bindonly");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+ @Test
+ public void testUnbindOnly() {
+ Element dep = getDependencyById(deps, "unbindonly");
+ String opt = dep.getAttribute("comparator");
+ assertEquals("Check comparator", "org.apache.felix.ipojo.runtime.core.test.components.MyComparator", opt);
+ }
+
+
+ private Element getDependencyById(Element[] deps, String name) {
+ for (int i = 0; i < deps.length; i++) {
+ String na = deps[i].getAttribute("id");
+ String field = deps[i].getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return deps[i];
+ }
+ }
+ fail("Dependency " + name + " not found");
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestServiceProviding.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestServiceProviding.java
new file mode 100644
index 0000000..c923939
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestServiceProviding.java
@@ -0,0 +1,204 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+
+import java.util.List;
+
+import static junit.framework.Assert.*;
+
+public class TestServiceProviding extends Common {
+
+ @Test
+ public void testProvidesSimple() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesSimple");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ }
+
+ @Test
+ public void testProvidesDouble() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesDouble");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ }
+
+ @Test
+ public void testProvidesTriple() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesTriple");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ Element prov = provs[0];
+ String itfs = prov.getAttribute("specifications");
+ List list = ParseUtils.parseArraysAsList(itfs);
+ assertTrue("Provides CS ", list.contains(CheckService.class.getName()));
+ }
+
+ @Test
+ public void testProvidesQuatro() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesQuatro");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ Element prov = provs[0];
+ String itfs = prov.getAttribute("specifications");
+ List list = ParseUtils.parseArraysAsList(itfs);
+ assertTrue("Provides CS ", list.contains(CheckService.class.getName()));
+ assertTrue("Provides Foo ", list.contains(FooService.class.getName()));
+ }
+
+ @Test
+ public void testProperties() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesProperties");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ Element prov = provs[0];
+ Element[] props = prov.getElements("property");
+ assertEquals("Number of properties", props.length, 5);
+ //Foo
+ Element foo = getPropertyByName(props, "foo");
+ assertEquals("Check foo field", "m_foo", foo.getAttribute("field"));
+ assertEquals("Check foo name", "foo", foo.getAttribute("name"));
+ //Bar
+ Element bar = getPropertyByName(props, "bar");
+ assertEquals("Check bar field", "bar", bar.getAttribute("field"));
+ assertEquals("Check bar value", "4", bar.getAttribute("value"));
+ assertEquals("Check mandatory value", "true", bar.getAttribute("mandatory"));
+ //Boo
+ Element boo = getPropertyByName(props, "boo");
+ assertEquals("Check boo field", "boo", boo.getAttribute("field"));
+ //Baa
+ Element baa = getPropertyByName(props, "baa");
+ assertEquals("Check baa field", "m_baa", baa.getAttribute("field"));
+ assertEquals("Check baa name", "baa", baa.getAttribute("name"));
+
+ //Bar
+ Element baz = getPropertyByName(props, "baz");
+ assertEquals("Check baz field", "m_baz", baz.getAttribute("field"));
+ assertEquals("Check baz name", "baz", baz.getAttribute("name"));
+ }
+
+ @Test
+ public void testStaticProperties() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.ProvidesStaticProperties");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ Element prov = provs[0];
+ Element[] props = prov.getElements("property");
+ assertEquals("Number of properties", props.length, 9);
+ //Prop1
+ Element foo = getPropertyByName(props, "prop1");
+ assertNull(foo.getAttribute("field"));
+ assertEquals("prop1", foo.getAttribute("value"));
+
+ //Prop2
+ Element prop2 = getPropertyByName(props, "prop2");
+ assertNull(prop2.getAttribute("field"));
+ assertNull(prop2.getAttribute("value"));
+
+ // Props
+ Element prop = getPropertyByName(props, "props");
+ assertNull(prop.getAttribute("field"));
+ assertEquals("{prop1, prop2}", prop.getAttribute("value"));
+
+ // Mandatory
+ Element mandatory = getPropertyByName(props, "mandatory1");
+ assertNull(mandatory.getAttribute("field"));
+ assertNull(mandatory.getAttribute("value"));
+ assertEquals("true", mandatory.getAttribute("mandatory"));
+
+ //Bar
+ Element bar = getPropertyByName(props, "bar");
+ assertEquals("Check bar field", "bar", bar.getAttribute("field"));
+ assertEquals("Check bar value", "4", bar.getAttribute("value"));
+ assertEquals("Check mandatory value", "true", bar.getAttribute("mandatory"));
+ //Boo
+ Element boo = getPropertyByName(props, "boo");
+ assertEquals("Check boo field", "boo", boo.getAttribute("field"));
+ //Baa
+ Element baa = getPropertyByName(props, "baa");
+ assertEquals("Check baa field", "m_baa", baa.getAttribute("field"));
+ assertEquals("Check baa name", "baa", baa.getAttribute("name"));
+
+ //Bar
+ Element baz = getPropertyByName(props, "baz");
+ assertEquals("Check baz field", "m_baz", baz.getAttribute("field"));
+ assertEquals("Check baz name", "baz", baz.getAttribute("name"));
+ }
+
+ @Test
+ public void testServiceController() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.PSServiceController");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ System.out.println(provs[0].toString());
+ assertNotNull(provs[0].getElements("controller"));
+ assertEquals(1, provs[0].getElements("controller").length);
+ assertEquals("false", provs[0].getElements("controller")[0].getAttribute("value"));
+ }
+
+ @Test
+ public void testServiceControllerWithSpecification() {
+ Element meta = IPOJOHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.PSServiceControllerSpec");
+ Element[] provs = meta.getElements("provides");
+ assertNotNull("Provides exists ", provs);
+ System.out.println(provs[0].toString());
+ assertNotNull(provs[0].getElements("controller"));
+ assertEquals(2, provs[0].getElements("controller").length);
+ assertEquals("false", provs[0].getElements("controller")[0].getAttribute("value"));
+ assertEquals(FooService.class.getName(), provs[0].getElements("controller")[0].getAttribute("specification"));
+ }
+
+ /**
+ * Checks that declared static properties.
+ * It used 'org.apache.felix.ipojo.runtime.core.test.components.components.ComponentWithProperties'
+ * This test is related to : https://issues.apache.org/jira/browse/FELIX-4053
+ */
+ @Test
+ public void testPublishedStaticProperties() {
+ ServiceReference reference = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(),
+ "instanceWithProperties");
+ assertNotNull(reference);
+ }
+
+ private Element getPropertyByName(Element[] props, String name) {
+ for (Element prop : props) {
+ String na = prop.getAttribute("name");
+ String field = prop.getAttribute("field");
+ if (na != null && na.equalsIgnoreCase(name)) {
+ return prop;
+ }
+ if (field != null && field.equalsIgnoreCase(name)) {
+ return prop;
+ }
+ }
+ fail("Property " + name + " not found");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestTemporalDependencies.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestTemporalDependencies.java
new file mode 100644
index 0000000..31dc546
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestTemporalDependencies.java
@@ -0,0 +1,197 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+public class TestTemporalDependencies extends Common {
+
+
+ @Test
+ public void testSimple() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalSimple");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+ String to = provs[0].getAttribute("timeout");
+ assertNull("No timeout", to);
+ String oto = provs[0].getAttribute("onTimeout");
+ assertNull("No onTimeout", oto);
+ }
+
+ @Test
+ public void testTemporal() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.Temporal");
+ Element[] provs = meta.getElements("temporal", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+ String to = provs[0].getAttribute("timeout");
+ assertNull("No timeout", to);
+ String oto = provs[0].getAttribute("onTimeout");
+ assertNull("No onTimeout", oto);
+ }
+
+ @Test
+ public void testDI() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithDI");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String oto = provs[0].getAttribute("onTimeout");
+ assertEquals("onTimeout is the DI", "org.apache.felix.ipojo.runtime.core.test.components.ProvidesSimple", oto);
+
+ }
+
+ @Test
+ public void testEmptyArray() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithEmptyArray");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String oto = provs[0].getAttribute("onTimeout");
+ assertEquals("onTimeout is empty-array", "empty-array", oto);
+
+ }
+
+ @Test
+ public void testNull() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithNull");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String oto = provs[0].getAttribute("onTimeout");
+ assertEquals("onTimeout is null", "null", oto);
+
+ }
+
+ @Test
+ public void testNullable() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithNullable");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String oto = provs[0].getAttribute("onTimeout");
+ assertEquals("onTimeout is nullable", "nullable", oto);
+
+ }
+
+ @Test
+ public void testFilter() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithFilter");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String filter = provs[0].getAttribute("filter");
+ assertEquals("Filter", "(vendor=clement)", filter);
+
+ }
+
+ @Test
+ public void testTimeout() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalWithTimeout");
+ Element[] provs = meta.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ String field = provs[0].getAttribute("field");
+ assertNotNull("Field not null", field);
+ assertEquals("Field is fs", "fs", field);
+
+ String to = provs[0].getAttribute("timeout");
+ assertEquals("Check timeout", "100", to);
+
+ }
+
+ @Test
+ public void testSimpleCollection() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalCollection");
+ Element dep = getElementPerField(meta, "fs1");
+ String spec = dep.getAttribute("specification");
+ assertNotNull("Specification not null", spec);
+ assertEquals("Check specification", "org.apache.felix.ipojo.runtime.core.test.services.FooService", spec);
+ }
+
+ @Test
+ public void testCollectionWithTimeout() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalCollection");
+ Element dep = getElementPerField(meta, "fs2");
+ String spec = dep.getAttribute("specification");
+ assertNotNull("Specification not null", spec);
+ assertEquals("Check specification", "org.apache.felix.ipojo.runtime.core.test.services.FooService", spec);
+ String to = dep.getAttribute("timeout");
+ assertEquals("Check timeout", "300", to);
+ }
+
+ @Test
+ public void testCollectionWithPolicy() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalCollection");
+ Element dep = getElementPerField(meta, "fs3");
+ String spec = dep.getAttribute("specification");
+ assertNotNull("Specification not null", spec);
+ assertEquals("Check specification", "org.apache.felix.ipojo.runtime.core.test.services.FooService", spec);
+ String to = dep.getAttribute("ontimeout");
+ assertEquals("Check policy", "empty", to);
+ }
+
+ @Test
+ public void testCollectionWithProxy() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), "org.apache.felix.ipojo.runtime.core.test.components.temporal.TemporalCollection");
+ Element dep = getElementPerField(meta, "fs4");
+ String spec = dep.getAttribute("specification");
+ assertNotNull("Specification not null", spec);
+ assertEquals("Check specification", "org.apache.felix.ipojo.runtime.core.test.services.FooService", spec);
+ String proxy = dep.getAttribute("proxy");
+ assertEquals("Check proxy", "true", proxy);
+ }
+
+ private Element getElementPerField(Element elem, String field) {
+ Element[] provs = elem.getElements("requires", "org.apache.felix.ipojo.handler.temporal");
+ assertNotNull("Temporal exists ", provs);
+ for (int i = 0; i < provs.length; i++) {
+ if (provs[i].getAttribute("field").equals(field)) {
+ return provs[i];
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestWhiteBoard.java b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestWhiteBoard.java
new file mode 100644
index 0000000..097ba9c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-annotations-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/annotations/TestWhiteBoard.java
@@ -0,0 +1,108 @@
+/*
+ * 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.test.annotations;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TestWhiteBoard extends Common {
+
+ String typeWI = "org.apache.felix.ipojo.runtime.core.test.components.whiteboard.WhiteBoardWIModification";
+ String typeWO = "org.apache.felix.ipojo.runtime.core.test.components.whiteboard.WhiteBoardWOModification";
+ String typeWhiteboards = "org.apache.felix.ipojo.runtime.core.test.components.whiteboard.WhiteBoards";
+ String namespace = "org.apache.felix.ipojo.whiteboard";
+
+
+ @Test
+ public void testMetadataWithOnModification() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), typeWI);
+ assertNotNull("Check meta", meta);
+ Element[] ext = meta.getElements("wbp", namespace);
+ assertEquals("Check size", 1, ext.length);
+ String filter = ext[0].getAttribute("filter");
+ String onArr = ext[0].getAttribute("onArrival");
+ String onDep = ext[0].getAttribute("onDeparture");
+ String onMod = ext[0].getAttribute("onModification");
+
+
+ assertEquals("Check filter", "(foo=true)", filter);
+ assertEquals("Check onArrival", "onArrival", onArr);
+ assertEquals("Check onDeparture", "onDeparture", onDep);
+ assertEquals("Check onModification", "onModification", onMod);
+
+ }
+
+ @Test
+ public void testMetadataWithoutOnModification() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), typeWO);
+ assertNotNull("Check meta", meta);
+ Element[] ext = meta.getElements("wbp", namespace);
+ assertEquals("Check size", 1, ext.length);
+ String filter = ext[0].getAttribute("filter");
+ String onArr = ext[0].getAttribute("onArrival");
+ String onDep = ext[0].getAttribute("onDeparture");
+ String onMod = ext[0].getAttribute("onModification");
+
+
+ assertEquals("Check filter", "(foo=true)", filter);
+ assertEquals("Check onArrival", "onArrival", onArr);
+ assertEquals("Check onDeparture", "onDeparture", onDep);
+ assertNull("Check onModification", onMod);
+
+ }
+
+ @Test
+ public void testWhiteboards() {
+ Element meta = ipojoHelper.getMetadata(getTestBundle(), typeWhiteboards);
+ assertNotNull("Check meta", meta);
+ Element[] ext = meta.getElements("whiteboards", namespace);
+ assertEquals("Check size", 1, ext.length);
+
+ // Two sub-element
+ Element[] wbps = ext[0].getElements("wbp", namespace);
+ assertEquals("Check size", 2, wbps.length);
+
+ String filter = wbps[0].getAttribute("filter");
+ String onArr = wbps[0].getAttribute("onArrival");
+ String onDep = wbps[0].getAttribute("onDeparture");
+ String onMod = wbps[0].getAttribute("onModification");
+
+ assertEquals("Check filter", "(foo=true)", filter);
+ assertEquals("Check onArrival", "onArrival", onArr);
+ assertEquals("Check onDeparture", "onDeparture", onDep);
+ assertNull("Check onModification", onMod);
+
+ filter = wbps[1].getAttribute("filter");
+ onArr = wbps[1].getAttribute("onArrival");
+ onDep = wbps[1].getAttribute("onDeparture");
+ onMod = wbps[1].getAttribute("onModification");
+
+ assertEquals("Check filter", "(foo=true)", filter);
+ assertEquals("Check onArrival", "onArrival", onArr);
+ assertEquals("Check onDeparture", "onDeparture", onDep);
+ assertEquals("Check onModification", "onModification", onMod);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/pom.xml
new file mode 100644
index 0000000..53edfc0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-bad-configuration-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/BadConstructors.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/BadConstructors.java
new file mode 100644
index 0000000..54b3c2d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/BadConstructors.java
@@ -0,0 +1,40 @@
+/*
+ * 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.bad.components;
+
+public class BadConstructors {
+
+ public BadConstructors() {
+ throw new Error("BAD");
+ }
+
+ public BadConstructors(int i) {
+ // DO NOTHING
+ }
+
+ public static BadConstructors createBad() {
+ throw new RuntimeException("BAD");
+ }
+
+ public static BadConstructors createBad2(int o) {
+ return new BadConstructors(o);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CallbackCheckService.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CallbackCheckService.java
new file mode 100644
index 0000000..b768a00
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CallbackCheckService.java
@@ -0,0 +1,68 @@
+/*
+ * 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.bad.components;
+
+import org.apache.felix.ipojo.runtime.bad.services.CheckService;
+import org.apache.felix.ipojo.runtime.bad.services.FooService;
+
+import java.util.Properties;
+
+public class CallbackCheckService extends ParentClass implements CheckService {
+
+ int i = 0;
+
+ FooService fs;
+
+ public static CallbackCheckService singleton;
+
+ public static int count = 0;
+
+ private static CallbackCheckService singleton() {
+ if (singleton == null) {
+ count++;
+ singleton = new CallbackCheckService();
+ }
+ return singleton;
+ }
+
+ public static CallbackCheckService several() {
+ count++;
+ return new CallbackCheckService();
+ }
+
+ private void start() {
+ i++;
+ }
+
+ protected void stop() {
+ i++;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties p = new Properties();
+ p.put("int", new Integer(i));
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..abd757b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.bad.components;
+
+import org.apache.felix.ipojo.runtime.bad.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckServiceProvider.java
new file mode 100644
index 0000000..2bb5908
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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.bad.components;
+
+import org.apache.felix.ipojo.runtime.bad.services.CheckService;
+import org.apache.felix.ipojo.runtime.bad.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/LifecycleControllerTest.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/LifecycleControllerTest.java
new file mode 100644
index 0000000..ed544f6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/LifecycleControllerTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.bad.components;
+
+import org.apache.felix.ipojo.runtime.bad.services.CheckService;
+
+import java.util.Properties;
+
+public class LifecycleControllerTest implements CheckService {
+
+ private boolean m_state = true;
+ private String m_conf;
+
+ public void setConf(String newConf) {
+ if (newConf.equals("foo")) {
+ m_state = true;
+ } else {
+ m_state = false;
+ }
+ }
+
+ public boolean check() {
+ return m_state;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("conf", m_conf);
+ props.put("state", new Boolean(m_state));
+ return props;
+ }
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/ParentClass.java
new file mode 100644
index 0000000..3f5cd24
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.bad.components;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/BarService.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/BarService.java
new file mode 100644
index 0000000..e204c9f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.bad.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/CheckService.java
new file mode 100644
index 0000000..79025f8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.bad.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/FooService.java
new file mode 100644
index 0000000..1d3c907
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/bad/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.bad.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..f2308b3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/main/resources/metadata.xml
@@ -0,0 +1,71 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <!-- No XSD as this file violates the format -->
+ <component
+ className="org.apache.felix.ipojo.runtime.bad.components.CallbackCheckService"
+ name="BAD-CallbackCheckService" architecture="true">
+ <requires field="fs" />
+ <provides />
+ <callback transition="validate" method="start" />
+ <callback transition="invalidate" method="stop" />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.bad.components.LifecycleControllerTest"
+ name="BAD-lcTest">
+ <provides />
+ <controller field="m_state" />
+ <properties>
+ <property name="conf" field="m_conf" method="setConf" />
+ </properties>
+ </component>
+
+ <component
+ className="org.apache.felix.ipojo.runtime.bad.components.CheckServiceProvider"
+ name="BAD-BothCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Bad constructors -->
+ <component
+ className="org.apache.felix.ipojo.runtime.bad.components.BadConstructors"
+ name="BAD-BadConstructor"
+ immediate="true"
+ />
+
+ <component
+ className="org.apache.felix.ipojo.runtime.bad.components.BadConstructors"
+ factory-method="createBad"
+ name="BAD-BadFactory"
+ immediate="true"
+ />
+
+ <component
+ className="org.apache.felix.ipojo.runtime.bad.components.BadConstructors"
+ factory-method="createBad2"
+ name="BAD-BadFactory2"
+ immediate="true"
+ />
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/Common.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/Common.java
new file mode 100644
index 0000000..a25d9c9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/Common.java
@@ -0,0 +1,31 @@
+/*
+ * 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.bad.test;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ // Nothing to customize.
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadFactories.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadFactories.java
new file mode 100644
index 0000000..08f79ca
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadFactories.java
@@ -0,0 +1,140 @@
+/*
+ * 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.bad.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+public class TestBadFactories extends Common {
+
+ private Element getElementFactoryWithNoClassName() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("name", "noclassname"));
+ return elem;
+ }
+
+ private Element getElementHandlerFactoryWithNoClassName() {
+ Element elem = new Element("handler", "");
+ elem.addAttribute(new Attribute("name", "noclassname"));
+ return elem;
+ }
+
+ private Element getElementHandlerFactoryWithNoName() {
+ Element elem = new Element("handler", "");
+ elem.addAttribute(new Attribute("className", "noclassname"));
+ return elem;
+ }
+
+ @Test
+ public void testBadFactory() {
+ try {
+ new ComponentFactory(osgiHelper.getContext(), getElementFactoryWithNoClassName());
+ fail("A factory with no class name must be rejected");
+ } catch (ConfigurationException e) {
+ // OK.
+ }
+ }
+
+ @Test
+ public void testBadHandlerFactory1() {
+ try {
+ new HandlerManagerFactory(osgiHelper.getContext(), getElementHandlerFactoryWithNoClassName());
+ fail("An handler factory with no class name must be rejected");
+ } catch (ConfigurationException e) {
+ // OK.
+ }
+ }
+
+ @Test
+ public void testBadHandlerFactory2() {
+ try {
+ new HandlerManagerFactory(osgiHelper.getContext(), getElementHandlerFactoryWithNoName());
+ fail("An handler factory with no name must be rejected");
+ } catch (ConfigurationException e) {
+ // OK.
+ }
+ }
+
+ @Test
+ public void testCreationOnBadConstructor() {
+ Factory factory = ipojoHelper.getFactory("BAD-BadConstructor");
+ ComponentInstance ci;
+ try {
+ // Change in Felix-966, now throws a runtime exception
+ ci = factory.createComponentInstance(null);
+ //assertEquals("Check ci create error", ComponentInstance.STOPPED, ci.getState());
+ ci.dispose();
+ fail("Exception expected");
+ } catch (Throwable e) {
+ //fail("Exception unexpected : " + e.getMessage());
+ // OK
+ }
+ }
+
+ @Test
+ public void testCreationOnBadFactory() {
+ Factory factory = ipojoHelper.getFactory("BAD-BadFactory");
+ ComponentInstance ci;
+ try {
+ // Change in Felix-966, now throw a runtime exception
+ ci = factory.createComponentInstance(null);
+ //assertEquals("Check ci create error", ComponentInstance.STOPPED, ci.getState());
+ ci.dispose();
+ fail("Exception expected");
+ } catch (Throwable e) {
+ //fail("Exception unexpected : " + e.getMessage());
+ //OK
+ }
+ }
+
+ @Test
+ public void testCreationOnBadFactory2() {
+ Factory factory = ipojoHelper.getFactory("BAD-BadFactory2");
+ ComponentInstance ci;
+ try {
+ // Change in Felix-966, now throw a runtime exception
+ ci = factory.createComponentInstance(null);
+ //assertEquals("Check ci create error", ComponentInstance.STOPPED, ci.getState());
+ ci.dispose();
+ fail("Exception expected");
+ } catch (Throwable e) {
+ //fail("Exception unexpected : " + e.getMessage());
+ //Ok
+ }
+ }
+
+ @Test
+ public void testNoManipulationMetadata() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", "org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"));
+ try {
+ ComponentFactory fact = new ComponentFactory(osgiHelper.getContext(), elem);
+ fact.stop();
+ fail("A factory with no manipulation metadata must be rejected");
+ } catch (ConfigurationException e) {
+ // OK.
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCCallback.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCCallback.java
new file mode 100644
index 0000000..2574099
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCCallback.java
@@ -0,0 +1,262 @@
+/*
+ * 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.bad.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestBadLFCCallback extends Common {
+
+ private String clazz = "org.apache.felix.ipojo.runtime.bad.components.CallbackCheckService";
+ private String type = "BAD-CallbackCheckService";
+ private Element manipulation;
+ private Properties props;
+
+ @Before
+ public void setUp() {
+ manipulation = getManipulationForComponent();
+ props = new Properties();
+ props.put("instance.name", "BAD");
+ }
+
+
+ private Element getNothing() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getNoTransition() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("method", "start"));
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getNoMethod() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("transition", "validate"));
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadMethod() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("transition", "validate"));
+ callback.addAttribute(new Attribute("method", "start_")); // Missing method.
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadMethod2() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("transition", "invalidate"));
+ callback.addAttribute(new Attribute("method", "stop_")); // Missing method.
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadTransition() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("method", "start"));
+ callback.addAttribute(new Attribute("transition", "validate_"));
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getManipulationForComponent() {
+ // On KF we must cast the result.
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getManipulationForComponent(elem, type);
+ assertNotNull("Check manipulation metadata not null for " + type, manip);
+ return manip;
+ }
+
+ private Element getManipulationForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for (int i = 0; i < comps.length; i++) {
+ if (comps[i].containsAttribute("factory") && comps[i].getAttribute("factory").equals(comp_name)) {
+ return comps[i].getElements("manipulation")[0];
+ }
+ if (comps[i].containsAttribute("name") && comps[i].getAttribute("name").equals(comp_name)) {
+ return comps[i].getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testNothing() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNothing());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A lifecycle callback with a missing method and transition must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNoTransition() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNoTransition());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A lifecycle callback with a missing transition must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNoMethod() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNoMethod());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A lifecycle callback with a missing method must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadMethod() {
+ try {
+ ComponentFactory cf = new ComponentFactory(getTestBundle().getBundleContext(), getBadMethod());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ if (ci.isStarted()) {
+ fail("A lifecycle callback with a bad method must be rejected (instance stills valid)" + cf);
+ }
+ ci.dispose();
+ cf.stop();
+ } catch (ConfigurationException e) {
+ //The check does not happen in the configure method.
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadMethod2() {
+ try {
+ ComponentFactory cf = new ComponentFactory(getTestBundle().getBundleContext(), getBadMethod2());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.stop();
+ if (ci.isStarted()) {
+ fail("A lifecycle callback with a bad method must be rejected (instance stills valid)" + cf);
+ }
+ ci.dispose();
+ cf.stop();
+ } catch (ConfigurationException e) {
+ //The check does not happen in the configure method.
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadTransition() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadTransition());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A lifecycle callback with a bad transition must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCController.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCController.java
new file mode 100644
index 0000000..814c882
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadLFCController.java
@@ -0,0 +1,106 @@
+/*
+ * 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.bad.test;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestBadLFCController extends Common {
+
+ private String clazz = "org.apache.felix.ipojo.test.scenarios.component.LifecycleControllerTest";
+
+ private Element getNoFieldController() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element controller = new Element("controller", "");
+ elem.addElement(controller);
+ return elem;
+ }
+
+ private Element getBadFieldController() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element controller = new Element("controller", "");
+ controller.addAttribute(new Attribute("field", "controller")); // Missing field
+ elem.addElement(controller);
+ elem.addElement(getManipulationForComponent("BAD-lcTest"));
+ return elem;
+ }
+
+ private Element getManipulationForComponent(String comp_name) {
+ // On KF we must cast the result
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getManipulationForComponent(elem, comp_name);
+ assertNotNull("Check manipulation metadata not null for " + comp_name, manip);
+ return manip;
+ }
+
+ private Element getManipulationForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for (Element comp : comps) {
+ if (comp.containsAttribute("name") && comp.getAttribute("name").equals(comp_name)) {
+ return comp.getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testNoField() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNoFieldController());
+ cf.start();
+ cf.stop();
+ fail("A lifecycle controller with a missing field must be rejected " + cf);
+ } catch (Exception e) {
+ // OK
+ }
+ }
+
+ @Test
+ public void testBadField() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadFieldController());
+ cf.start();
+ cf.stop();
+ fail("A lifecycle controller with a bad field must be rejected " + cf);
+ } catch (Exception e) {
+ // OK
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadServiceDependencies.java b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadServiceDependencies.java
new file mode 100644
index 0000000..03133fe
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/bad/test/TestBadServiceDependencies.java
@@ -0,0 +1,370 @@
+/*
+ * 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.bad.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.runtime.bad.services.BarService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestBadServiceDependencies extends Common {
+
+ private String clazz = "org.apache.felix.ipojo.test.scenarios.component.CheckServiceProvider";
+ private String type = "BAD-BothCheckServiceProvider";
+ private Element manipulation;
+ private Properties props;
+
+ @Before
+ public void setUp() {
+ manipulation = getManipulationForComponent();
+ props = new Properties();
+ props.put("instance.name", "BAD");
+ }
+
+
+ private Element getNothing() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getNoField() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ callback.addAttribute(new Attribute("filter", "(foo=bar)"));
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadField() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ callback.addAttribute(new Attribute("field", "BAD_FIELD")); // missing field.
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadFilter() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ callback.addAttribute(new Attribute("field", "fs"));
+ callback.addAttribute(new Attribute("filter", "(foo=bar)&(bar=foo)")); // Incorrect filter
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadFrom() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ callback.addAttribute(new Attribute("field", "fs"));
+ callback.addAttribute(new Attribute("from", "ba(d&_")); // Incorrect from
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getBadType() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ Element callback = new Element("requires", "");
+ callback.addAttribute(new Attribute("field", "fs"));
+ callback.addAttribute(new Attribute("interface", BarService.class.getName()));
+ elem.addElement(callback);
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getMissingSpecification() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ // iPOJO cannot determine the specification of this type of dependency.
+ Element dependency = new Element("requires", "");
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("type", "bind"));
+ callback.addAttribute(new Attribute("method", "refBind"));
+ dependency.addElement(callback);
+ elem.addElement(dependency);
+
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getMissingCallbackType() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ // iPOJO cannot determine the specification of this type of dependency.
+ Element dependency = new Element("requires", "");
+ dependency.addAttribute(new Attribute("field", "fs"));
+ Element callback = new Element("callback", "");
+ // callback.addAttribute(new Attribute("type", "bind")); --> Type missing.
+ callback.addAttribute(new Attribute("method", "refBind"));
+ dependency.addElement(callback);
+ elem.addElement(dependency);
+
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+ private Element getMissingCallbackMethod() {
+ Element elem = new Element("component", "");
+ elem.addAttribute(new Attribute("classname", clazz));
+
+ // iPOJO cannot determine the specification of this type of dependency.
+ Element dependency = new Element("requires", "");
+ dependency.addAttribute(new Attribute("field", "fs"));
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("type", "bind"));
+ // callback.addAttribute(new Attribute("method", "refBind")); --> Method missing.
+ dependency.addElement(callback);
+ elem.addElement(dependency);
+
+ elem.addElement(manipulation);
+ return elem;
+ }
+
+
+ private Element getManipulationForComponent() {
+ // On KF we must cast the result.
+ String header = (String) getTestBundle().getHeaders().get("iPOJO-Components");
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parse(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getManipulationForComponent(elem, type);
+ assertNotNull("Check manipulation metadata not null for " + type, manip);
+ return manip;
+ }
+
+ private Element getManipulationForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for (Element comp : comps) {
+ if (comp.containsAttribute("factory") && comp.getAttribute("factory").equals(comp_name)) {
+ return comp.getElements("manipulation")[0];
+ }
+ if (comp.containsAttribute("name") && comp.getAttribute("name").equals(comp_name)) {
+ return comp.getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testNothing() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNothing());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with neither field and method must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNoField() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getNoField());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with neither field and method must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadField() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadField());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad field must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadFilter() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadFilter());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad filter must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ //OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadFrom() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadFrom());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad from must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ //OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadType() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getBadType());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad type must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check that a component using a service dependency without service specification is rejected.
+ */
+ @Test
+ public void testDependencyWithoutSpecification() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getMissingSpecification());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad type must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check that a component using a service dependency with a callback without its type is rejected.
+ * The type is either 'bind' or 'unbind'.
+ */
+ @Test
+ public void testDependencyWithACallbackWithoutType() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getMissingCallbackType());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad type must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check that a component using a service dependency with a callback without its method is rejected.
+ */
+ @Test
+ public void testDependencyWithACallbackWithoutMethod() {
+ try {
+ ComponentFactory cf = new ComponentFactory(osgiHelper.getContext(), getMissingCallbackMethod());
+ cf.start();
+ ComponentInstance ci = cf.createComponentInstance(props);
+ ci.dispose();
+ cf.stop();
+ fail("A service requirement with a bad type must be rejected " + cf);
+ } catch (ConfigurationException e) {
+ // OK
+ } catch (UnacceptableConfiguration e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail("Unexpected exception when creating an instance : " + e.getMessage());
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/resources/exam.properties b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/resources/exam.properties
new file mode 100644
index 0000000..d8a500d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-bad-configuration-test/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/pom.xml
new file mode 100644
index 0000000..9f51ce2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-configuration-admin-test</artifactId>
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProvider.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProvider.java
new file mode 100644
index 0000000..f0df68f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class ConfigurableFooProvider implements FooService {
+
+ private String message; // Configurable property
+ private int invokeCount = 0;
+
+ public void setMessage(String message) {
+ System.err.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;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProviderWithPropagation.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProviderWithPropagation.java
new file mode 100644
index 0000000..01898b7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableFooProviderWithPropagation.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+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.FooService;
+
+import java.util.Properties;
+
+@Component(propagation = true)
+@Provides
+public class ConfigurableFooProviderWithPropagation implements FooService {
+
+ @Property
+ private String message;
+
+ @Property(name=".private")
+ private String myPrivateLife;
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties props = new Properties();
+ if (message == null) {
+ props.put("message", "NULL");
+ } else {
+ props.put("message", message);
+ }
+ return props;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateConfigurableFooProvider.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateConfigurableFooProvider.java
new file mode 100644
index 0000000..236007d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ImmediateConfigurableFooProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+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.annotations.Updated;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+@Component(propagation = true, immediate = true)
+@Provides
+public class ImmediateConfigurableFooProvider implements FooService {
+
+ @Property
+ private String message;
+
+ @Property(name=".private")
+ private String myPrivateLife;
+
+ private Dictionary configuration;
+ private int count;
+
+ @Updated
+ public void updated(Dictionary conf) {
+ System.out.println("Updating component with " + conf);
+ this.configuration = conf;
+ this.count++;
+ }
+
+ 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", count);
+
+ return props;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return count;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..c3d38ec
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..716115f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..c9e02c0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/main/resources/metadata.xml
@@ -0,0 +1,40 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableFooProvider"
+ name="CA-ConfigurableProvider">
+ <provides/>
+ <properties>
+ <property name="message" method="setMessage"/>
+ </properties>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableFooProvider"
+ immediate="true"
+ name="CA-ImmConfigurableProvider">
+ <provides/>
+ <properties>
+ <property name="message" method="setMessage"/>
+ </properties>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..ce43d70
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.helpers.ConfigAdminHelper;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+public class Common extends BaseTest {
+
+ public static int UPDATE_WAIT_TIME = 2000;
+
+ public ConfigAdminHelper caHelper = null;
+
+ public ConfigurationAdmin admin;
+
+ public void grace() {
+ TimeUtils.grace(UPDATE_WAIT_TIME);
+ }
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Before
+ public void initializeConfigAdmin() {
+ caHelper = new ConfigAdminHelper(bc);
+ admin = caHelper.getConfigurationAdmin();
+ caHelper.deleteAllConfigurations();
+ }
+
+ @After
+ public void stoppingConfigAdmin() {
+ caHelper.deleteAllConfigurations();
+ caHelper.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForImmediate.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForImmediate.java
new file mode 100644
index 0000000..8e1e346
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForImmediate.java
@@ -0,0 +1,346 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+public class TestManagedServiceFactoryTestForImmediate extends Common {
+
+ private ComponentFactory factory;
+
+ @Before
+ public void setUp() {
+ factory = (ComponentFactory) ipojoHelper.getFactory("CA-ImmConfigurableProvider");
+ }
+
+ @Test
+ public void testCreationAndReconfiguration() {
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", "?");
+ } 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();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 2, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testCreationAndReconfiguration2() {
+ //The reconfiguration happens before the service invocation
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", "?");
+ } 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);
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Check object -2", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ //Invoke
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = ((Integer) p.get("count")).intValue();
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 2, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testDelayedCreationAndReconfiguration() {
+ factory.stop();
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", "?");
+ } 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();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ assertNull("check no instance", osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+
+ factory.start();
+
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ // architecture = (Architecture) osgiHelper.getServiceObject( 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, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testDelayedCreationAndReconfiguration2() {
+ factory.stop();
+ //The reconfiguration happens before the service invocation
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", "?");
+ } 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();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ assertNull("check no instance", osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+
+ factory.start();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Check object -1", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ //Invoke
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 2, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForServices.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForServices.java
new file mode 100644
index 0000000..11865c8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceFactoryTestForServices.java
@@ -0,0 +1,356 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestManagedServiceFactoryTestForServices extends Common {
+
+ private ComponentFactory factory;
+
+ @Before
+ public void setUp() {
+ factory = (ComponentFactory) ipojoHelper.getFactory("CA-ConfigurableProvider");
+ }
+
+ @Test
+ public void testMSFCreationAndReconfiguration() {
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", "?");
+ } 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
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ osgiHelper.waitForService(FooService.class.getName(), "(instance.name=" + pid + ")", 1000);
+
+ ServiceReference refx = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNotNull("Check refx", refx);
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNotNull("Check fs", fs);
+
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ Dictionary p2 = configuration.getProperties();
+ p2.put("message", "message2");
+ try {
+ System.err.println("The configuration will be updated with message2");
+
+ configuration.update(p2);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ System.err.println("The configuration should be updated with message2");
+
+ fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 2, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testMSFCreationAndReconfiguration2() {
+ //The reconfiguration happens before the service invocation
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", "?");
+ } 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();
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Check no object -2", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ //Invoke
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testDelayedCreationAndReconfiguration() {
+ factory.stop();
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", "?");
+ } 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();
+
+ assertNull("check no instance", osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+
+ factory.start();
+
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ osgiHelper.waitForService(FooService.class.getName(), "(instance.name=" + pid + ")", 1000);
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ System.out.println("===");
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ System.out.println("===");
+
+ fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 2, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+ @Test
+ public void testDelayedCreationAndReconfiguration2() {
+ factory.stop();
+ //The reconfiguration happens before the service invocation
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", "?");
+ } 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", osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+
+ factory.start();
+
+
+ // The instance should be created, wait for the architecture service
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=" + pid + ")", 1000);
+ Architecture architecture = (Architecture) osgiHelper.getServiceObject(Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ props.put("message", "message2");
+ try {
+ configuration.update(props);
+ // Update the configuration ...
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ //architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Check no object -2", 0, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ //Invoke
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), "(instance.name=" + pid + ")");
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ // architecture = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance="+pid+")");
+
+ assertEquals("Assert Message", "message2", mes);
+ assertEquals("Assert count", 1, count);
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) architecture.getInstanceDescription()).getCreatedObjects().length);
+
+ try {
+ configuration.delete();
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = osgiHelper.getServiceReference(FooService.class.getName(), "(instance.name=" + pid + ")");
+ assertNull("Check unavailability", ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForImmediate.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForImmediate.java
new file mode 100644
index 0000000..d655bc5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForImmediate.java
@@ -0,0 +1,368 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestManagedServiceTestForImmediate extends Common {
+
+ private String factNameImm = "CA-ImmConfigurableProvider";
+ private String msp = "foo";
+
+ private ComponentFactory factImm;
+
+ @Before
+ public void setUp() throws InterruptedException {
+ factImm = (ComponentFactory) ipojoHelper.getFactory(factNameImm);
+ }
+
+ @Test
+ public void testFactoryCreationAndReconfigurationUsingManagedService() {
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp); // Exposes a ManagedService.
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factImm.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message", mes);
+ assertEquals("Check count", 1, count);
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ System.err.println("updated ? ");
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message2", mes);
+ assertEquals("Check count", 2, count);
+
+ instance.dispose();
+ }
+
+ /**
+ * Creates an instance using a factory configuration.
+ * The configuration specifies the managed.service.pid property
+ * Reconfiguration is applied using the exposed managed service.
+ */
+ @Test
+ public void testCreationUsingFactoryConfigurationSettingTheManagedServicePid() {
+ Configuration conf = null;
+ try {
+ conf = admin.createFactoryConfiguration(factNameImm, getTestBundle().getLocation());
+ Dictionary props = conf.getProperties();
+ if (props == null) {
+ props = new Properties();
+ }
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ conf.update(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+
+ Architecture arch = (Architecture) osgiHelper.getServiceObject(org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), conf.getPid());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message", mes);
+ assertEquals("Check count", 1, count);
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), conf.getPid());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ if (mes.equals("message")) {
+ System.out.println("Warning, configuration not yet applied");
+ assertEquals("Check count - W", 1, count);
+ } else {
+ assertEquals("Check message", "message2", mes);
+ assertEquals("Check count", 2, count);
+ }
+
+ try {
+ conf.delete();
+ grace();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @Test
+ public void testCreationAndReconfiguration2() {
+ // The configuration exists before the instance creation.
+
+ //Update
+ Configuration configuration = null;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factImm.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ // int count1 = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message - 1 (" + mes + ")", "message2", mes); // Already reconfigured.
+ // assertEquals("Check count", 2, count); // Two : 1) "message" on immediate, "message2" on the reconfiguration,
+ // not necessary as the property can be set before the immediate instance creation
+
+ instance.dispose();
+
+ //Reconfiguration
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message3");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Recreation of the instance.
+ props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ instance = null;
+ try {
+ instance = factImm.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ // int count = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message already reconfigured", "message3", mes); // Already reconfigured.
+ //assertEquals("Check count", count1 + 1, count); // message before the reconfiguration, message3 after the reconfiguration
+
+ instance.dispose();
+
+
+ }
+
+ @Test
+ public void testCreationAndReconfiguration3() {
+ // The configuration exists before the instance creation.
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factImm.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ // int count = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message2", mes); // Already reconfigured.
+ //assertEquals("Check count", 1, count);
+
+ //Reconfiguration
+ try {
+ configuration = admin.getConfiguration(msp);
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message3");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ instance.dispose();
+
+ // Recreation of the instance.
+ props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ instance = null;
+ try {
+ instance = factImm.createComponentInstance(props);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Wait until the configuration is delivered.
+ grace();
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ // count = ((Integer) p.get("count")).intValue();
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message3", mes); // Already reconfigured.
+ // assertEquals("Check count", 1, count);
+
+ instance.dispose();
+
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForService.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForService.java
new file mode 100644
index 0000000..5b4f849
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceTestForService.java
@@ -0,0 +1,362 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestManagedServiceTestForService extends Common {
+
+ private String factNameSvc = "CA-ConfigurableProvider";
+ private String msp = "foo";
+ private ComponentFactory factSvc;
+
+ @Before
+ public void setUp() {
+ factSvc = (ComponentFactory) ipojoHelper.getFactory(factNameSvc);
+ }
+
+ @Test
+ public void testCreationUsingFactoryAndReconfigurationUsingManagedService() {
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factSvc.createComponentInstance(props);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message", mes);
+ assertEquals("Check count", 1, count);
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ if (mes.equals("message")) {
+ System.out.println("Warning, configuration not yet applied");
+ assertEquals("Check count - W", 1, count);
+ } else {
+ assertEquals("Check message", "message2", mes);
+ assertEquals("Check count", 2, count);
+ }
+
+ instance.dispose();
+
+ }
+
+ @Test
+ public void testCreationUsingMSFAndReconfigurationUsingManagedService() {
+ Configuration conf = null;
+ try {
+ conf = admin.createFactoryConfiguration(factNameSvc, getTestBundle().getLocation());
+ Dictionary props = conf.getProperties();
+ if (props == null) {
+ props = new Properties();
+ }
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ conf.update(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ Architecture arch = (Architecture) osgiHelper.getServiceObject(org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), conf.getPid());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message", mes);
+ assertEquals("Check count", 1, count);
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), conf.getPid());
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ // arch = (Architecture) osgiHelper.getServiceObject( org.apache.felix.ipojo.architecture.Architecture.class.getName(), "(architecture.instance=" + conf.getPid() + ")");
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) arch.getInstanceDescription()).getCreatedObjects().length);
+ if (mes.equals("message")) {
+ System.out.println("Warning, configuration not yet applied");
+ assertEquals("Check count - W", 1, count);
+ } else {
+ assertEquals("Check message", "message2", mes);
+ assertEquals("Check count", 2, count);
+ }
+
+ try {
+ conf.delete();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @Test
+ public void testConfigurationPushedBeforeInstantiationUsingFactory() {
+ // The configuration exists before the instance creation.
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ //listener.waitForEvent(msp, "1");
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factSvc.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message2", mes); // Already reconfigured.
+ assertEquals("Check count", 1, count);
+
+ instance.dispose();
+
+ //Reconfiguration
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message3");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Recreation of the instance.
+ props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ instance = null;
+ try {
+ instance = factSvc.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message3", mes); // Already reconfigured.
+ assertEquals("Check count", 1, count);
+
+ instance.dispose();
+
+
+ }
+
+ @Test
+ public void testConfigurationPushedBeforeInstantiationUsingFactoryAndReconfiguration() {
+ // The configuration exists before the instance creation.
+
+ //Update
+ Configuration configuration;
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message2");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ Properties props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ ComponentInstance instance = null;
+ try {
+ instance = factSvc.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ FooService fs = (FooService) bc.getService(ref);
+ Properties p = fs.fooProps();
+ String mes = p.getProperty("message");
+ int count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message2", mes); // Already reconfigured.
+ assertEquals("Check count", 1, count);
+
+ //Reconfiguration
+ try {
+ configuration = admin.getConfiguration(msp, getTestBundle().getLocation());
+ Dictionary prc = configuration.getProperties();
+ if (prc == null) {
+ prc = new Properties();
+ }
+ prc.put("message", "message3");
+ configuration.update(prc);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ instance.dispose();
+
+ // Recreation of the instance.
+ props = new Properties();
+ props.put("managed.service.pid", msp);
+ props.put("message", "message");
+ instance = null;
+ try {
+ instance = factSvc.createComponentInstance(props);
+ grace();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertEquals("Check no object", 0, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertNotNull("FS availability", ref);
+
+ fs = (FooService) bc.getService(ref);
+ p = fs.fooProps();
+ mes = p.getProperty("message");
+ count = (Integer) p.get("count");
+ assertEquals("Check 1 object", 1, ((PrimitiveInstanceDescription) instance.getInstanceDescription()).getCreatedObjects().length);
+ assertEquals("Check message", "message3", mes); // Already reconfigured.
+ assertEquals("Check count", 1, count);
+
+ instance.dispose();
+
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropagation.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropagation.java
new file mode 100644
index 0000000..962c51a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropagation.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+/**
+ * Test for FELIX-4207 - ipojo @Component with propagation set to true doesn't propagate properties
+ */
+public class TestPropagation extends Common {
+
+ private String factoryName = "org.apache.felix.ipojo.runtime.core.components.ConfigurableFooProviderWithPropagation";
+
+ @Test
+ public void testPropagationFromConfigurationAdminWhenCreatingTheInstance() throws IOException {
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("message", "message");
+ props.put("propagated", "propagated");
+ props.put(".private", "wow");
+
+ Configuration configuration = admin.createFactoryConfiguration(factoryName, "?");
+ configuration.update(props);
+
+ ServiceReference ref = osgiHelper.waitForService(FooService.class.getName(),
+ "(instance.name=" + configuration.getPid() + ")",
+ 1000);
+
+ // Check the propagation
+ assertEquals(ref.getProperty("propagated"), "propagated");
+ assertEquals(ref.getProperty("message"), "message");
+ assertNull(ref.getProperty(".private"));
+ assertNull(ref.getProperty("private"));
+
+ // Check the the .private property has the right value
+ ConfigurationHandlerDescription desc = (ConfigurationHandlerDescription) ipojoHelper.getArchitectureByName(configuration.getPid())
+ .getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:properties");
+ PropertyDescription prop = desc.getPropertyByName(".private");
+ assertEquals(prop.getValue(), "wow");
+
+ // Update the property
+ props.put("message", "message2");
+ props.put("propagated", "propagated2");
+ props.put(".private", "wow2");
+ configuration.update(props);
+
+ grace();
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), configuration.getPid());
+ // Check the propagation
+ assertEquals(ref.getProperty("propagated"), "propagated2");
+ assertEquals(ref.getProperty("message"), "message2");
+
+ desc = (ConfigurationHandlerDescription) ipojoHelper.getArchitectureByName(configuration.getPid())
+ .getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:properties");
+ prop = desc.getPropertyByName(".private");
+ assertEquals(prop.getValue(), "wow2");
+
+ configuration.delete();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdated.java b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdated.java
new file mode 100644
index 0000000..0f71b61
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-admin-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdated.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+
+/**
+ * Test for FELIX-4172 Updated method called twice at the bundle start
+ */
+public class TestUpdated extends Common {
+
+ private String factoryName = "org.apache.felix.ipojo.runtime.core.components.ImmediateConfigurableFooProvider";
+
+ @Test
+ public void testNumberOfUpdatedCalls() throws IOException {
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("message", "message");
+ props.put("propagated", "propagated");
+ props.put(".private", "wow");
+
+ Configuration configuration = admin.createFactoryConfiguration(factoryName, "?");
+ configuration.update(props);
+
+ FooService fs = osgiHelper.waitForService(FooService.class,
+ "(instance.name=" + configuration.getPid() + ")",
+ 1000);
+
+ assertEquals(fs.getInt(), 1);
+
+ // Update the property
+ props.put("message", "message2");
+ props.put("propagated", "propagated2");
+ props.put(".private", "wow2");
+ configuration.update(props);
+
+ grace();
+
+ assertEquals(fs.getInt(), 2);
+
+ // Remove a property
+ props.remove("propagated");
+ configuration.update(props);
+
+ grace();
+
+ assertEquals(fs.getInt(), 3);
+
+
+ configuration.delete();
+ }
+
+ @Test
+ public void testNumberOfUpdatedCallsWithManagedService() throws IOException {
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("message", "message");
+ props.put("propagated", "propagated");
+ props.put(".private", "wow");
+ props.put("managed.service.pid", "config");
+
+ Configuration configuration = admin.createFactoryConfiguration(factoryName, "?");
+ configuration.update(props);
+
+ FooService fs = osgiHelper.waitForService(FooService.class,
+ "(instance.name=" + configuration.getPid() + ")",
+ 1000);
+
+ assertEquals(fs.getInt(), 1);
+
+ // Update the property using the managed service.
+
+ Configuration managedConfiguration = admin.getConfiguration("config", "?");
+ props.put("message", "message2");
+ props.put("propagated", "propagated2");
+ props.put(".private", "wow2");
+ managedConfiguration.update(props);
+
+ grace();
+
+ assertEquals(fs.getInt(), 2);
+
+ // Remove a property
+ props.remove("propagated");
+ managedConfiguration.update(props);
+
+ grace();
+
+ assertEquals(fs.getInt(), 3);
+
+ managedConfiguration.delete();
+ configuration.delete();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/pom.xml
new file mode 100644
index 0000000..0d5fff7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-configuration-processor-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Bean.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Bean.java
new file mode 100644
index 0000000..7b0d406
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/Bean.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * A bean
+ */
+public class Bean {
+
+ private String message;
+
+ private int count;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureAnotherInstance.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureAnotherInstance.java
new file mode 100644
index 0000000..f5b5c3c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureAnotherInstance.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class ConfigureAnotherInstance {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance anotherInstance = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureNothing.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureNothing.java
new file mode 100644
index 0000000..c3c6588
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureNothing.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+
+/**
+ * Nothing happen in this class..
+ */
+@Configuration
+public class ConfigureNothing {
+
+ // Nothing on purpose
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureOneInstance.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureOneInstance.java
new file mode 100644
index 0000000..d3f2511
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureOneInstance.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class ConfigureOneInstance {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureThreeInstancesUsingMethods.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureThreeInstancesUsingMethods.java
new file mode 100644
index 0000000..58c05a8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureThreeInstancesUsingMethods.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration using methods and fields.
+ */
+@Configuration
+public class ConfigureThreeInstancesUsingMethods {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+
+ Instance instance1() {
+ return instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+ }
+
+ Instance instance2(BundleContext bc) {
+ return instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(bc.getBundles().length)
+ .with("props").setto(new Properties());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstances.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstances.java
new file mode 100644
index 0000000..0dfb520
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstances.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class ConfigureTwoInstances {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance1 = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+
+ // Declare an instance of MyComponent named hello
+ Instance myInstance2 = instance().of(MyComponent.class)
+ .named("hello")
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithInheritance.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithInheritance.java
new file mode 100644
index 0000000..c290747
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithInheritance.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class ConfigureTwoInstancesWithInheritance extends ParentConfiguration {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance1 = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithOverridding.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithOverridding.java
new file mode 100644
index 0000000..564bc67
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigureTwoInstancesWithOverridding.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class ConfigureTwoInstancesWithOverridding extends ParentConfiguration {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance1 = instance().of(MyComponent.class)
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+
+ protected Instance myInstance2 = instance().of(MyComponent.class)
+ .named("hello-over")
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComplexComponent.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComplexComponent.java
new file mode 100644
index 0000000..b61512d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComplexComponent.java
@@ -0,0 +1,106 @@
+/*
+ * 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;
+
+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.FooService;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A complex component
+ */
+@Component
+@Provides
+public class MyComplexComponent implements FooService {
+
+ @Property
+ private File file;
+ @Property
+ private Bean bean;
+ @Property
+ private Map<String, String> map;
+
+ @Override
+ public boolean foo() {
+ return file != null;
+ }
+
+ @Override
+ public Properties fooProps() {
+ String content;
+ try {
+ content = read();
+ } catch (IOException e) {
+ throw new IllegalStateException("unexpected error", e);
+ }
+ Properties props = new Properties();
+ props.put("map", map);
+ props.put("content", content);
+ props.put("bean", bean);
+ return props;
+ }
+
+ private String read() throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String line;
+ StringBuilder stringBuilder = new StringBuilder();
+ String ls = System.getProperty("line.separator");
+
+ while ((line = reader.readLine()) != null) {
+ stringBuilder.append(line);
+ stringBuilder.append(ls);
+ }
+
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public Boolean getObject() {
+ return false;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return false;
+ }
+
+ @Override
+ public int getInt() {
+ return 0;
+ }
+
+ @Override
+ public long getLong() {
+ return 1;
+ }
+
+ @Override
+ public double getDouble() {
+ return 1;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
new file mode 100644
index 0000000..bbd5a44
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+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.annotations.ServiceProperty;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A simple component
+ */
+@Component
+@Provides
+public class MyComponent implements FooService {
+
+ @Property
+ private Boolean bool;
+
+ @Property
+ private Properties props;
+
+ @ServiceProperty
+ private String message;
+
+ @Property
+ private long number;
+
+ @Property
+ private int integer;
+
+ @Property
+ private double floating;
+
+ @Override
+ public boolean foo() {
+ return message != null;
+ }
+
+ @Override
+ public Properties fooProps() {
+ return props;
+ }
+
+ @Override
+ public Boolean getObject() {
+ return bool;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return bool;
+ }
+
+ @Override
+ public int getInt() {
+ return integer;
+ }
+
+ @Override
+ public long getLong() {
+ return number;
+ }
+
+ @Override
+ public double getDouble() {
+ return floating;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfiguration.java
new file mode 100644
index 0000000..f8c9481
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * This configuration is a parent configuration.
+ */
+public class ParentConfiguration {
+
+ // Inherited fields must be public.
+ protected Instance myInstance2 = instance().of(MyComponent.class)
+ .named("hello")
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+
+ private Instance hidden = instance().of(MyComponent.class)
+ .named("hello")
+ .with("floating").setto("1.0")
+ .with("message").setto("hidden")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleConfiguration.java
new file mode 100644
index 0000000..314fb8c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration
+ */
+@Configuration
+public class SimpleConfiguration {
+
+ // Declare an instance of MyComponent named myInstance
+ Instance myInstance = instance().of(MyComponent.class)
+ .named("foo");
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyComplexConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyComplexConfiguration.java
new file mode 100644
index 0000000..3aed514
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyComplexConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ * 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.configuration;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+import org.apache.felix.ipojo.runtime.core.components.Bean;
+import org.apache.felix.ipojo.runtime.core.components.MyComplexComponent;
+import org.osgi.framework.BundleContext;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+
+import static org.apache.felix.ipojo.configuration.Instance.*;
+
+/**
+ * A complex configuration creating two instances of MyComplex component
+ */
+@Configuration
+public class MyComplexConfiguration {
+
+ Instance complex1(BundleContext bc) throws FileNotFoundException {
+
+ File file = bc.getBundle().getDataFile("file1.txt");
+ write(file, "I'm file 1");
+
+ Bean bean = new Bean();
+ bean.setMessage("I'm 1");
+ bean.setCount(1);
+
+ return instance().of(MyComplexComponent.class)
+ .with("file").setto(file)
+ .with("bean").setto(bean)
+ .with("map").setto(map(pair("a", "b"), pair("c", "d")));
+
+ }
+
+ Instance complex2(BundleContext bc) throws FileNotFoundException {
+
+ File file = bc.getBundle().getDataFile("file2.txt");
+ write(file, "I'm file 2");
+
+ Bean bean = new Bean();
+ bean.setMessage("I'm 2");
+ bean.setCount(2);
+
+ return instance().of(MyComplexComponent.class)
+ .with("file").setto(file)
+ .with("bean").setto(bean)
+ .with("map").setto(map(pair("a", "b2"), pair("c", "d2")));
+
+ }
+
+ private void write(File file, String message) throws FileNotFoundException {
+ PrintWriter out = new PrintWriter(file);
+ out.println(message);
+ out.close();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java
new file mode 100644
index 0000000..5d2cf8d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java
@@ -0,0 +1,45 @@
+/*
+ * 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.configuration;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+
+import java.util.Properties;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+/**
+ * Simple configuration in another package.
+ */
+@Configuration
+public class MyConfiguration {
+
+ // Declare an instance of MyComponent named myInstance
+ // We use the factory name to avoid import-export package.
+ Instance myInstance = instance().of("org.apache.felix.ipojo.runtime.core.components.MyComponent")
+ .with("floating").setto("1.0")
+ .with("message").setto("foo")
+ .with("bool").setto(true)
+ .with("number").setto(1l)
+ .with("integer").setto(1)
+ .with("props").setto(new Properties());
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..8b2ba0d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.components"
+ );
+ }
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexConfigurations.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexConfigurations.java
new file mode 100644
index 0000000..2e08f71
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexConfigurations.java
@@ -0,0 +1,145 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.runtime.core.components.Bean;
+import org.apache.felix.ipojo.runtime.core.components.MyComplexComponent;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.configuration.MyComplexConfiguration;
+import org.apache.felix.ipojo.runtime.core.components.configuration.MyConfiguration;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check @Configuration embedded in another bundle using complex configurations.
+ */
+public class TestComplexConfigurations extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComplexComponent.class)
+ .add(Bean.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.components")
+ .build(IPOJOStrategy.withiPOJO())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComplexConfiguration.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Configuration")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ /**
+ * <ol>
+ * <li>Check when all bundles are deployed</li>
+ * <li>Check when the configuration bundle is stopped</li>
+ * <li>Check when the configuration is restarted</li>
+ * <li>Check when the component bundle is stopped</li>
+ * <li>Check when the component bundle is restarted</li>
+ * </ol>
+ */
+ @Test
+ public void testDynamism() throws BundleException {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+ //1)
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+
+ //2) Stopping configuration bundle
+ osgiHelper.getBundle("Configuration").stop();
+ Assert.assertNull(osgiHelper.getServiceReference(FooService.class));
+
+ //3) Restart configuration bundle
+ osgiHelper.getBundle("Configuration").start();
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+
+ //4) Stop the component bundle
+ osgiHelper.getBundle("MyComponent").stop();
+ Assert.assertNull(osgiHelper.getServiceReference(FooService.class));
+
+ //5) Restart the component bundle
+ osgiHelper.getBundle("MyComponent").start();
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ FooService fs1 = ipojoHelper.getServiceObjectByName(FooService.class, "complex1");
+ Properties props1 = fs1.fooProps();
+ Assert.assertTrue(((String)props1.get("content")).contains("I'm file 1"));
+ Assert.assertEquals(((Bean)props1.get("bean")).getMessage(), "I'm 1");
+ Assert.assertEquals(((Bean)props1.get("bean")).getCount(), 1);
+ Assert.assertEquals(((Map<String, String>)props1.get("map")).get("a"), "b");
+
+ FooService fs2 = ipojoHelper.getServiceObjectByName(FooService.class, "complex2");
+ Assert.assertNotNull(fs2);
+ Properties props2 = fs2.fooProps();
+ Assert.assertTrue(((String)props2.get("content")).contains("I'm file 2"));
+ Assert.assertEquals(((Bean)props2.get("bean")).getMessage(), "I'm 2");
+ Assert.assertEquals(((Bean)props2.get("bean")).getCount(), 2);
+ Assert.assertEquals(((Map<String, String>)props2.get("map")).get("a"), "b2");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationInAnotherBundle.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationInAnotherBundle.java
new file mode 100644
index 0000000..3911bd1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationInAnotherBundle.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.configuration.MyConfiguration;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check @Configuration embedded in another bundle.
+ */
+public class TestConfigurationInAnotherBundle extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyConfiguration.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Configuration")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ /**
+ * <ol>
+ * <li>Check when all bundles are deployed</li>
+ * <li>Check when the configuration bundle is stopped</li>
+ * <li>Check when the configuration is restarted</li>
+ * <li>Check when the component bundle is stopped</li>
+ * <li>Check when the component bundle is restarted</li>
+ * </ol>
+ */
+ @Test
+ public void testDynamism() throws BundleException {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+ //1)
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+
+ //2) Stopping configuration bundle
+ osgiHelper.getBundle("Configuration").stop();
+ Assert.assertNull(osgiHelper.getServiceReference(FooService.class));
+
+ //3) Restart configuration bundle
+ osgiHelper.getBundle("Configuration").start();
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+
+ //4) Stop the component bundle
+ osgiHelper.getBundle("MyComponent").stop();
+ Assert.assertNull(osgiHelper.getServiceReference(FooService.class));
+
+ //5) Restart the component bundle
+ osgiHelper.getBundle("MyComponent").start();
+ osgiHelper.waitForService(FooService.class, null, 10000);
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfMyComponent.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfMyComponent.java
new file mode 100644
index 0000000..e02df8a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfMyComponent.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureOneInstance;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check simple @Configuration
+ */
+public class TestConfigurationOfMyComponent extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .add(ConfigureOneInstance.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() throws IOException {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check configuration
+ FooService fs = osgiHelper.getServiceObject(FooService.class);
+ Assert.assertTrue(fs.foo());
+ Assert.assertEquals(fs.getDouble(), 1.0, 0);
+ Assert.assertEquals(fs.getInt(), 1);
+ Assert.assertEquals(fs.getLong(), 1l);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfThreeInstancesUsingMethods.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfThreeInstancesUsingMethods.java
new file mode 100644
index 0000000..03c726f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfThreeInstancesUsingMethods.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureThreeInstancesUsingMethods;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureTwoInstances;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check a @Configuration with 2 instances.
+ */
+public class TestConfigurationOfThreeInstancesUsingMethods extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(ConfigureThreeInstancesUsingMethods.class)
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check we have three instances
+ ServiceReference[] refs = osgiHelper.getServiceReferences(FooService.class, null);
+ Assert.assertEquals(refs.length, 3);
+
+ List<Architecture> arch = osgiHelper.getServiceObjects(Architecture.class, null);
+ for (Architecture a : arch) {
+ System.out.println("Instance " + a.getInstanceDescription().getName());
+ }
+
+ // Check name
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "myInstance"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "instance1"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "instance2"));
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfTwoInstances.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfTwoInstances.java
new file mode 100644
index 0000000..7f162e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationOfTwoInstances.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureTwoInstances;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check a @Configuration with 2 instances.
+ */
+public class TestConfigurationOfTwoInstances extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(ConfigureTwoInstances.class)
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check we have two instances
+ ServiceReference[] refs = osgiHelper.getServiceReferences(FooService.class, null);
+ Assert.assertEquals(refs.length, 2);
+
+ List<Architecture> arch = osgiHelper.getServiceObjects(Architecture.class, null);
+ for (Architecture a : arch) {
+ System.out.println("Instance " + a.getInstanceDescription().getName());
+ }
+
+ // Check name
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "hello"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "myInstance1"));
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithInheritedInstance.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithInheritedInstance.java
new file mode 100644
index 0000000..d0b0c68
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithInheritedInstance.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureTwoInstancesWithInheritance;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.ParentConfiguration;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check a @Configuration inheriting an instance from a parent class.
+ */
+public class TestConfigurationWithInheritedInstance extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(ConfigureTwoInstancesWithInheritance.class)
+ .add(ParentConfiguration.class)
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check we have two instances
+ ServiceReference[] refs = osgiHelper.getServiceReferences(FooService.class, null);
+ Assert.assertEquals(refs.length, 2);
+
+ List<Architecture> arch = osgiHelper.getServiceObjects(Architecture.class, null);
+ for (Architecture a : arch) {
+ System.out.println("Instance " + a.getInstanceDescription().getName());
+ }
+
+ // Check name
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "hello"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "myInstance1"));
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithOverriddenInstance.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithOverriddenInstance.java
new file mode 100644
index 0000000..a537953
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurationWithOverriddenInstance.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureTwoInstancesWithOverridding;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.ParentConfiguration;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check a @Configuration overriding instance declaration.
+ */
+public class TestConfigurationWithOverriddenInstance extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(ConfigureTwoInstancesWithOverridding.class)
+ .add(ParentConfiguration.class)
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check we have two instances
+ ServiceReference[] refs = osgiHelper.getServiceReferences(FooService.class, null);
+ Assert.assertEquals(refs.length, 2);
+
+ List<Architecture> arch = osgiHelper.getServiceObjects(Architecture.class, null);
+ for (Architecture a : arch) {
+ System.out.println("Instance " + a.getInstanceDescription().getName());
+ }
+
+ // Check name
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "hello-over"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "myInstance1"));
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestEmptyConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestEmptyConfiguration.java
new file mode 100644
index 0000000..7ca2d69
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestEmptyConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureNothing;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check an empty @Configuration
+ */
+public class TestEmptyConfiguration extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .add(ConfigureNothing.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() throws InterruptedException {
+ TimeUtils.grace(1000);
+ // Check configuration
+ Assert.assertNull(osgiHelper.getServiceReference(FooService.class));
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConfigurations.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConfigurations.java
new file mode 100644
index 0000000..571669a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSeveralConfigurations.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureAnotherInstance;
+import org.apache.felix.ipojo.runtime.core.components.ConfigureOneInstance;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check several configuration @Configuration in the same bundle.
+ */
+public class TestSeveralConfigurations extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(ConfigureOneInstance.class)
+ .add(ConfigureAnotherInstance.class)
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+
+ TimeUtils.grace(500);
+ osgiHelper.waitForService(FooService.class, null, 10000);
+
+ // Check we have two instances
+ ServiceReference[] refs = osgiHelper.getServiceReferences(FooService.class, null);
+ Assert.assertEquals(refs.length, 2);
+
+ List<Architecture> arch = osgiHelper.getServiceObjects(Architecture.class, null);
+ for (Architecture a : arch) {
+ System.out.println("Instance " + a.getInstanceDescription().getName());
+ }
+
+ // Check name
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "anotherInstance"));
+ Assert.assertNotNull(ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "myInstance"));
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleConfiguration.java
new file mode 100644
index 0000000..52c7614
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-processor-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleConfiguration.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.SimpleConfiguration;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check a simple @Configuration
+ */
+public class TestSimpleConfiguration extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ // Build a service bundle
+ return OptionUtils.combine(options,
+ streamBundle(
+ TinyBundles.bundle()
+ .add(FooService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .add(SimpleConfiguration.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO())
+ )
+ );
+ }
+
+ @Test
+ public void testConfiguration() throws InterruptedException {
+ if (isKnopflerfish()) {
+ return; // Test disabled on KF
+ }
+ TimeUtils.grace(1000);
+ // Check configuration
+ Assert.assertNotNull(osgiHelper.getServiceReference(FooService.class));
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-configuration-test/pom.xml
new file mode 100644
index 0000000..f58b9ac
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-configuration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComplexConfiguration.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComplexConfiguration.java
new file mode 100644
index 0000000..9edfc1f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComplexConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class ComplexConfiguration implements CheckService {
+
+ private List m_list;
+ private Map m_map;
+ private Dictionary m_dict;
+ private String[] m_array;
+
+ private List m_complexList;
+ private Map m_complexMap;
+ private Object[] m_complexArray;
+
+ public boolean check() {
+ return true;
+ }
+
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("list", m_list);
+ props.put("map", m_map);
+ props.put("dict", m_dict);
+ props.put("array", m_array);
+ props.put("complex-list", m_complexList);
+ props.put("complex-map", m_complexMap);
+ props.put("complex-array", m_complexArray);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableCheckServiceProvider.java
new file mode 100644
index 0000000..315f443
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableCheckServiceProvider.java
@@ -0,0 +1,223 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class ConfigurableCheckServiceProvider implements CheckService {
+
+ // Integer types
+ byte b;
+ short s;
+ int i;
+ long l;
+
+ // Floatting types
+ double d;
+ float f;
+
+ // Character
+ char c;
+
+ // Boolean
+ boolean bool;
+
+ // Integer arrays
+ byte[] bs;
+ short[] ss;
+ int[] is;
+ long[] ls;
+
+ double[] ds;
+ float[] fs;
+
+ char[] cs;
+
+ boolean[] bools;
+
+ String string;
+ String[] strings;
+
+ int upB, upS, upI, upL, upD, upF, upC, upBool, upBs, upSs, upIs, upLs, upDs, upFs, upCs, upBools, upString, upStrings;
+
+
+ public boolean check() {
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("b", new Byte(b));
+ props.put("s", new Short(s));
+ props.put("i", new Integer(i));
+ props.put("l", new Long(l));
+ props.put("d", new Double(d));
+ props.put("f", new Float(f));
+ props.put("c", new Character(c));
+ props.put("bool", new Boolean(bool));
+
+ if (bs != null) {
+ props.put("bs", bs);
+ }
+ if (ss != null) {
+ props.put("ss", ss);
+ }
+ if (is != null) {
+ props.put("is", is);
+ }
+ if (ls != null) {
+ props.put("ls", ls);
+ }
+ if (ds != null) {
+ props.put("ds", ds);
+ }
+ if (fs != null) {
+ props.put("fs", fs);
+ }
+ if (cs != null) {
+ props.put("cs", cs);
+ }
+ if (bools != null) {
+ props.put("bools", bools);
+ }
+
+ props.put("upb", new Integer(upB));
+ props.put("ups", new Integer(upS));
+ props.put("upi", new Integer(upI));
+ props.put("upl", new Integer(upL));
+ props.put("upd", new Integer(upD));
+ props.put("upf", new Integer(upF));
+ props.put("upc", new Integer(upC));
+ props.put("upbool", new Integer(upBool));
+
+ props.put("upbs", new Integer(upBs));
+ props.put("upss", new Integer(upSs));
+ props.put("upis", new Integer(upIs));
+ props.put("upls", new Integer(upLs));
+ props.put("upds", new Integer(upDs));
+ props.put("upfs", new Integer(upFs));
+ props.put("upcs", new Integer(upCs));
+ props.put("upbools", new Integer(upBools));
+
+ if (string != null) {
+ props.put("string", string);
+ }
+ if (string != null) {
+ props.put("strings", strings);
+ }
+
+ props.put("upstring", new Integer(upString));
+ props.put("upstrings", new Integer(upStrings));
+
+ return props;
+ }
+
+ public void updateB(byte bb) {
+ b = bb;
+ upB++;
+ }
+
+ public void updateS(short bb) {
+ s = bb;
+ upS++;
+ }
+
+ public void updateI(int bb) {
+ i = bb;
+ upI++;
+ }
+
+ public void updateL(long bb) {
+ l = bb;
+ upL++;
+ }
+
+ public void updateD(double bb) {
+ d = bb;
+ upD++;
+ }
+
+ public void updateF(float bb) {
+ f = bb;
+ upF++;
+ }
+
+ public void updateC(char bb) {
+ c = bb;
+ upC++;
+ }
+
+ public void updateBool(boolean bb) {
+ bool = bb;
+ upBool++;
+ }
+
+ public void updateBs(byte[] bb) {
+ bs = bb;
+ upBs++;
+ }
+
+ public void updateSs(short[] bb) {
+ ss = bb;
+ upSs++;
+ }
+
+ public void updateIs(int[] bb) {
+ is = bb;
+ upIs++;
+ }
+
+ public void updateLs(long[] bb) {
+ ls = bb;
+ upLs++;
+ }
+
+ public void updateDs(double[] bb) {
+ ds = bb;
+ upDs++;
+ }
+
+ public void updateFs(float[] bb) {
+ fs = bb;
+ upFs++;
+ }
+
+ public void updateCs(char[] bb) {
+ cs = bb;
+ upCs++;
+ }
+
+ public void updateBools(boolean[] bb) {
+ bools = bb;
+ upBools++;
+ }
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..3c09096
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,134 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private int updated;
+ private Dictionary lastupdated;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+
+ p.put("updated", new Integer(updated));
+ if (lastupdated != null) {
+ p.put("lastupdated", lastupdated);
+ }
+
+
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+ public void updated(Dictionary props) {
+ updated++;
+ lastupdated = props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType2.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType2.java
new file mode 100644
index 0000000..90237cf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType2.java
@@ -0,0 +1,115 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType2 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static int count = 0;
+
+ private int updated;
+
+
+ public FooProviderType2(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+
+ p.put("updated", new Integer(updated));
+
+
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType2(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+ public void updated() {
+ updated++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..9ccddd6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+ private int updated;
+ private Dictionary lastUpdate;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp == null || strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ if (strProp != null) {
+ p.put("strProp", strProp);
+ }
+ if (strAProp != null) {
+ p.put("strAProp", strAProp);
+ }
+ if (intAProp != null) {
+ p.put("intAProp", intAProp);
+ }
+
+ p.put("updated", new Integer(updated));
+ if (lastUpdate != null) {
+ p.put("lastupdated", lastUpdate);
+ }
+
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ public void updated(Dictionary props) {
+ updated++;
+ lastUpdate = props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
new file mode 100644
index 0000000..33d385c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfigurableCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfigurableCheckServiceProvider.java
new file mode 100644
index 0000000..aaafb3c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentConfigurableCheckServiceProvider.java
@@ -0,0 +1,194 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class ParentConfigurableCheckServiceProvider extends ParentClass implements CheckService {
+
+ // Integer types
+ byte b;
+ short s;
+ int i;
+ long l;
+
+ // Floatting types
+ double d;
+ float f;
+
+ // Character
+ char c;
+
+ // Boolean
+ boolean bool;
+
+ // Integer arrays
+ byte[] bs;
+ short[] ss;
+ int[] is;
+ long[] ls;
+
+ double[] ds;
+ float[] fs;
+
+ char[] cs;
+
+ boolean[] bools;
+
+ //String string;
+ //String[] strings;
+
+ int upB, upS, upI, upL, upD, upF, upC, upBool, upBs, upSs, upIs, upLs, upDs, upFs, upCs, upBools/*, upString, upStrings*/;
+
+
+ public boolean check() {
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("b", new Byte(b));
+ props.put("s", new Short(s));
+ props.put("i", new Integer(i));
+ props.put("l", new Long(l));
+ props.put("d", new Double(d));
+ props.put("f", new Float(f));
+ props.put("c", new Character(c));
+ props.put("bool", new Boolean(bool));
+
+ props.put("bs", bs);
+ props.put("ss", ss);
+ props.put("is", is);
+ props.put("ls", ls);
+ props.put("ds", ds);
+ props.put("fs", fs);
+ props.put("cs", cs);
+ props.put("bools", bools);
+
+ props.put("upb", new Integer(upB));
+ props.put("ups", new Integer(upS));
+ props.put("upi", new Integer(upI));
+ props.put("upl", new Integer(upL));
+ props.put("upd", new Integer(upD));
+ props.put("upf", new Integer(upF));
+ props.put("upc", new Integer(upC));
+ props.put("upbool", new Integer(upBool));
+
+ props.put("upbs", new Integer(upBs));
+ props.put("upss", new Integer(upSs));
+ props.put("upis", new Integer(upIs));
+ props.put("upls", new Integer(upLs));
+ props.put("upds", new Integer(upDs));
+ props.put("upfs", new Integer(upFs));
+ props.put("upcs", new Integer(upCs));
+ props.put("upbools", new Integer(upBools));
+
+ props.put("string", string);
+ props.put("strings", strings);
+ props.put("upstring", new Integer(upString));
+ props.put("upstrings", new Integer(upStrings));
+
+ return props;
+ }
+
+ public void updateB(byte bb) {
+ b = bb;
+ upB++;
+ }
+
+ public void updateS(short bb) {
+ s = bb;
+ upS++;
+ }
+
+ public void updateI(int bb) {
+ i = bb;
+ upI++;
+ }
+
+ public void updateL(long bb) {
+ l = bb;
+ upL++;
+ }
+
+ public void updateD(double bb) {
+ d = bb;
+ upD++;
+ }
+
+ public void updateF(float bb) {
+ f = bb;
+ upF++;
+ }
+
+ public void updateC(char bb) {
+ c = bb;
+ upC++;
+ }
+
+ public void updateBool(boolean bb) {
+ bool = bb;
+ upBool++;
+ }
+
+ public void updateBs(byte[] bb) {
+ bs = bb;
+ upBs++;
+ }
+
+ public void updateSs(short[] bb) {
+ ss = bb;
+ upSs++;
+ }
+
+ public void updateIs(int[] bb) {
+ is = bb;
+ upIs++;
+ }
+
+ public void updateLs(long[] bb) {
+ ls = bb;
+ upLs++;
+ }
+
+ public void updateDs(double[] bb) {
+ ds = bb;
+ upDs++;
+ }
+
+ public void updateFs(float[] bb) {
+ fs = bb;
+ upFs++;
+ }
+
+ public void updateCs(char[] bb) {
+ cs = bb;
+ upCs++;
+ }
+
+ public void updateBools(boolean[] bb) {
+ bools = bb;
+ upBools++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PropertyModifier.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PropertyModifier.java
new file mode 100644
index 0000000..d4fa3a7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/PropertyModifier.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class PropertyModifier implements CheckService {
+
+ private Class[] classes;
+ private BundleContext context;
+
+ PropertyModifier(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return classes != null;
+ }
+
+ public void setClasses(String[] classes) throws ClassNotFoundException {
+ Class[] cls = new Class[classes.length];
+ for (int i = 0; i < classes.length; i++) {
+ try {
+ cls[i] = context.getBundle().loadClass(classes[i]);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ this.classes = cls;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("classes", classes);
+ return props;
+ }
+
+}
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/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithBundleContextAndProperty.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithBundleContextAndProperty.java
new file mode 100644
index 0000000..da37d32
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithBundleContextAndProperty.java
@@ -0,0 +1,54 @@
+/*
+ * 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.constructor;
+
+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 org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+@Component(immediate = true)
+@Provides
+public class CheckServiceProviderWithBundleContextAndProperty implements CheckService {
+
+
+ private final String message;
+ private final BundleContext context;
+
+ public CheckServiceProviderWithBundleContextAndProperty(BundleContext context, @Property String message) {
+ this.message = message;
+ this.context = context;
+ }
+
+ public boolean check() {
+ return message != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("message", message);
+ props.put("context", context);
+
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithDefaultValueProperty.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithDefaultValueProperty.java
new file mode 100644
index 0000000..32e2c41
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithDefaultValueProperty.java
@@ -0,0 +1,51 @@
+/*
+ * 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.constructor;
+
+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;
+
+@Component(immediate = true)
+@Provides
+public class CheckServiceProviderWithDefaultValueProperty implements CheckService {
+
+
+ private final String message;
+
+ public CheckServiceProviderWithDefaultValueProperty(@Property(value = "message") String message) {
+ this.message = message;
+ }
+
+
+ public boolean check() {
+ return message != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("message", message);
+
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithNamedProperty.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithNamedProperty.java
new file mode 100644
index 0000000..cca6bfe
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithNamedProperty.java
@@ -0,0 +1,51 @@
+/*
+ * 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.constructor;
+
+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;
+
+@Component(immediate = true)
+@Provides
+public class CheckServiceProviderWithNamedProperty implements CheckService {
+
+
+ private final String message;
+
+ public CheckServiceProviderWithNamedProperty(@Property(name = "message") String message) {
+ this.message = message;
+ }
+
+
+ public boolean check() {
+ return message != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("message", message);
+
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithTwoProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithTwoProperties.java
new file mode 100644
index 0000000..eb25b5b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithTwoProperties.java
@@ -0,0 +1,54 @@
+/*
+ * 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.constructor;
+
+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;
+
+@Component(immediate = true)
+@Provides
+public class CheckServiceProviderWithTwoProperties implements CheckService {
+
+
+ private final String message;
+ private final String product;
+
+ public CheckServiceProviderWithTwoProperties(@Property String message, @Property(value="ipojo") String product) {
+ this.message = message;
+ this.product = product;
+ }
+
+
+ public boolean check() {
+ return message != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("message", message);
+ props.put("product", product);
+
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithUnnamedProperty.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithUnnamedProperty.java
new file mode 100644
index 0000000..cf79b0d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/constructor/CheckServiceProviderWithUnnamedProperty.java
@@ -0,0 +1,51 @@
+/*
+ * 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.constructor;
+
+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;
+
+@Component(immediate = true)
+@Provides
+public class CheckServiceProviderWithUnnamedProperty implements CheckService {
+
+
+ private final String message;
+
+ public CheckServiceProviderWithUnnamedProperty(@Property String message) {
+ this.message = message;
+ }
+
+
+ public boolean check() {
+ return message != null;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("message", message);
+
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..9b970ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/metadata.xml
@@ -0,0 +1,267 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="CONFIG-FooProviderType-Conf" architecture="true">
+ <provides />
+ <properties propagation="false">
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{1,2, 3}" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="CONFIG-FooProviderType-ConfNoValue" architecture="true">
+ <provides />
+ <properties propagation="false">
+ <property name="int" field="intProp"/>
+ <property name="boolean" field="boolProp"/>
+ <property name="string" field="strProp"/>
+ <property name="strAProp" field="strAProp"/>
+ <property name="intAProp" field="intAProp"/>
+ </properties>
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="CONFIG-FooProviderType-3" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+ <!-- Configuration Management Test -->
+ <component name="CONFIG-FieldConfigurableCheckService"
+ classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableCheckServiceProvider"
+ architecture="true">
+ <provides />
+ <properties propagation="true">
+ <property field="b" />
+ <property field="s" />
+ <property field="i" />
+ <property field="l" />
+ <property field="d" />
+ <property field="f" />
+ <property field="c" />
+ <property field="bool" />
+ <property field="bs" />
+ <property field="ss" />
+ <property field="is" />
+ <property field="ls" />
+ <property field="ds" />
+ <property field="fs" />
+ <property field="cs" />
+ <property field="bools" />
+ <property field="string" />
+ <property field="strings" />
+ </properties>
+ </component>
+
+ <component name="CONFIG-BothConfigurableCheckService"
+ classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableCheckServiceProvider"
+ architecture="true">
+ <provides />
+ <properties propagation="true">
+ <property field="b" method="updateB" />
+ <property field="s" method="updateS" />
+ <property field="i" method="updateI" />
+ <property field="l" method="updateL" />
+ <property field="d" method="updateD" />
+ <property field="f" method="updateF" />
+ <property field="c" method="updateC" />
+ <property field="bool" method="updateBool" />
+ <property field="bs" method="updateBs" />
+ <property field="ss" method="updateSs" />
+ <property field="is" method="updateIs" />
+ <property field="ls" method="updateLs" />
+ <property field="ds" method="updateDs" />
+ <property field="fs" method="updateFs" />
+ <property field="cs" method="updateCs" />
+ <property field="bools" method="updateBools" />
+ <property field="string" method="updateString" />
+ <property field="strings" method="updateStrings" />
+ </properties>
+ </component>
+
+ <component name="CONFIG-MethodConfigurableCheckService"
+ classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableCheckServiceProvider"
+ architecture="true">
+ <provides />
+ <properties propagation="true">
+ <property method="updateB" name="b" />
+ <property method="updateS" name="s" />
+ <property method="updateI" name="i" />
+ <property method="updateL" name="l" />
+ <property method="updateD" name="d" />
+ <property method="updateF" name="f" />
+ <property method="updateC" name="c" />
+ <property method="updateBool" name="bool" />
+ <property method="updateBs" name="bs" />
+ <property method="updateSs" name="ss" />
+ <property method="updateIs" name="is" />
+ <property method="updateLs" name="ls" />
+ <property method="updateDs" name="ds" />
+ <property method="updateFs" name="fs" />
+ <property method="updateCs" name="cs" />
+ <property method="updateBools" name="bools" />
+ <property method="updateString" name="string" />
+ <property method="updateStrings" name="strings" />
+ </properties>
+ </component>
+
+ <component name="CONFIG-ParentMethodConfigurableCheckService"
+ classname="org.apache.felix.ipojo.runtime.core.components.ParentConfigurableCheckServiceProvider"
+ architecture="true">
+ <provides />
+ <properties propagation="true">
+ <property method="updateB" name="b" />
+ <property method="updateS" name="s" />
+ <property method="updateI" name="i" />
+ <property method="updateL" name="l" />
+ <property method="updateD" name="d" />
+ <property method="updateF" name="f" />
+ <property method="updateC" name="c" />
+ <property method="updateBool" name="bool" />
+ <property method="updateBs" name="bs" />
+ <property method="updateSs" name="ss" />
+ <property method="updateIs" name="is" />
+ <property method="updateLs" name="ls" />
+ <property method="updateDs" name="ds" />
+ <property method="updateFs" name="fs" />
+ <property method="updateCs" name="cs" />
+ <property method="updateBools" name="bools" />
+ <property method="updateString" name="string" type="string" />
+ <property method="updateStrings" name="strings"
+ type="java.lang.String[]" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="CONFIG-FooProviderType-4" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true" pid="FooProvider-3">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComplexConfiguration">
+ <provides>
+ <property name="array" field="m_array"/>
+ <property name="complex-array" field="m_complexArray"/>
+ <property name="list" field="m_list"/>
+ <property name="complex-list" field="m_complexList"/>
+ <property name="map" field="m_map"/>
+ <property name="complex-map" field="m_complexMap"/>
+ <property name="dict" field="m_dict"/>
+ <property name="empty-array" type="String[]"/>
+ <property name="empty-map" type="java.util.HashMap"/>
+ <property name="empty-list" type="java.util.List"/>
+ </provides>
+ <properties>
+ <property name="array" field="m_array"/>
+ <property name="complex-array" field="m_complexArray"/>
+ <property name="list" field="m_list"/>
+ <property name="complex-list" field="m_complexList"/>
+ <property name="map" field="m_map"/>
+ <property name="complex-map" field="m_complexMap"/>
+ <property name="dict" field="m_dict"/>
+ </properties>
+ </component>
+
+ <instance component="org.apache.felix.ipojo.runtime.core.components.ComplexConfiguration" name="complex">
+ <property name="array" type="array">
+ <property value="a"/>
+ <property value="b"/>
+ </property>
+ <property name="list" type="list">
+ <property value="a"/>
+ <property value="b"/>
+ </property>
+ <property name="dict" type="dictionary">
+ <property name="a" value="a"/>
+ <property name="b" value="b"/>
+ </property>
+ <property name="map" type="map">
+ <property name="a" value="a"/>
+ <property name="b" value="b"/>
+ </property>
+ <property name="complex-array" type="array">
+ <property type="list">
+ <property value="a"/>
+ <property value="b"/>
+ </property>
+ <property type="list">
+ <property value="c"/>
+ <property value="d"/>
+ </property>
+ </property>
+ <property name="complex-list" type="list">
+ <property type="list">
+ <property value="a"/>
+ <property value="b"/>
+ </property>
+ <property type="list">
+ <property value="c"/>
+ <property value="d"/>
+ </property>
+ </property>
+ <property name="complex-map" type="map">
+ <property name="a" type="list">
+ <property value="a"/>
+ <property value="b"/>
+ </property>
+ <property name="b" type="list">
+ <property value="c"/>
+ <property value="d"/>
+ </property>
+ </property>
+ <property name="empty-array" type="array"/>
+ <property name="empty-list" type="list"/>
+ <property name="empty-map" type="map"/>
+ </instance>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.PropertyModifier">
+ <provides>
+ <property field="classes"/>
+ </provides>
+ <properties>
+ <property method="setClasses" name="cls"/>
+ </properties>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/updated.xml b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/updated.xml
new file mode 100644
index 0000000..89393e8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/resources/updated.xml
@@ -0,0 +1,103 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <!-- updated -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="CONFIG-FooProviderType-ConfUpdated" architecture="true">
+ <provides />
+ <properties updated="updated">
+ <property name="int" field="intProp" value="2" />
+ <property name="boolean" field="boolProp" value="false" />
+ <property name="string" field="strProp" value="foo" />
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" />
+ <property name="intAProp" field="intAProp" value="{1,2, 3}" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="CONFIG-FooProviderType-ConfNoValueUpdated" architecture="true">
+ <provides />
+ <properties updated="updated">
+ <property name="int" field="intProp"/>
+ <property name="boolean" field="boolProp"/>
+ <property name="string" field="strProp"/>
+ <property name="strAProp" field="strAProp"/>
+ <property name="intAProp" field="intAProp"/>
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="CONFIG-FooProviderType-4Updated" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true" pid="FooProvider-3" updated="updated">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType2"
+ name="CONFIG-FooProviderType-4Updated2" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true" pid="FooProvider-3" updated="updated">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="CONFIG-FooProviderType-3Updated" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true" updated="updated">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType2"
+ name="CONFIG-FooProviderType-3Updated2" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ <property name="baz" type="java.lang.String" />
+ </provides>
+ <properties propagation="true" updated="updated">
+ <property name="foo" field="m_foo" />
+ <property name="bar" field="m_bar" />
+ </properties>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..03bdbb6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.helpers.ConfigAdminHelper;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ public static int UPDATE_WAIT_TIME = 2000;
+
+ public ConfigAdminHelper caHelper = null;
+
+ public ConfigurationAdmin admin;
+
+ public void grace() {
+ TimeUtils.grace(UPDATE_WAIT_TIME);
+ }
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Before
+ public void initializeConfigAdmin() {
+ caHelper = new ConfigAdminHelper(bc);
+ admin = caHelper.getConfigurationAdmin();
+ caHelper.deleteAllConfigurations();
+ }
+
+ @After
+ public void stoppingConfigAdmin() {
+ caHelper.deleteAllConfigurations();
+ caHelper.dispose();
+ }
+}
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
new file mode 100644
index 0000000..8cbfc96
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestArchitecture.java
@@ -0,0 +1,236 @@
+/*
+ * 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;
+
+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.*;
+
+public class TestArchitecture extends Common {
+
+ /**
+ * Instance where the ManagedServicePID is provided by the component type.
+ */
+ ComponentInstance instance1;
+ /**
+ * Instance where the ManagedServicePID is provided by the instance.
+ */
+ ComponentInstance instance2;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-4";
+ Dictionary<String, String> p = new Hashtable<String, String>();
+ p.put("instance.name", "instance");
+ p.put("foo", "foo");
+ p.put("bar", "2");
+ p.put("baz", "baz");
+ instance1 = ipojoHelper.createComponentInstance(type, p);
+ assertEquals("instance1 created", ComponentInstance.VALID, instance1.getState());
+
+ type = "CONFIG-FooProviderType-3";
+ Dictionary<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance-2");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ p1.put("managed.service.pid", "instance");
+ instance2 = ipojoHelper.createComponentInstance(type, p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+
+ instance1 = null;
+ instance2 = null;
+ }
+
+ @Test
+ public void testArchitectureForInstance1() {
+
+ Architecture arch = osgiHelper.getServiceObject(Architecture.class,
+ "(architecture.instance=instance)");
+ assertNotNull(arch);
+
+ // Test on String representation.
+ String desc = arch.getInstanceDescription().getDescription().toString();
+ assertTrue(desc.contains("managed.service.pid=\"FooProvider-3\""));
+
+ // Test on handler description
+ ConfigurationHandlerDescription hd = (ConfigurationHandlerDescription) arch.getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:properties");
+ assertNotNull(hd);
+
+ assertEquals(2, hd.getProperties().length);
+ assertEquals("FooProvider-3", hd.getManagedServicePid());
+
+ // Check the getInstance() method
+ assertSame(arch.getInstanceDescription().getInstance(), instance1);
+
+ }
+
+ @Test
+ public void testArchitectureForInstance2() {
+ Architecture arch = osgiHelper.getServiceObject(Architecture.class, "(architecture.instance=instance-2)");
+ assertNotNull(arch);
+
+ // Test on String representation.
+ String desc = arch.getInstanceDescription().getDescription().toString();
+ assertTrue(desc.contains("managed.service.pid=\"instance\""));
+
+ // Test on handler description
+ ConfigurationHandlerDescription hd = (ConfigurationHandlerDescription) arch.getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:properties");
+ assertNotNull(hd);
+
+ assertEquals(2, hd.getProperties().length);
+ assertEquals("instance", hd.getManagedServicePid());
+
+ // Check the getInstance() method
+ assertSame(arch.getInstanceDescription().getInstance(), instance2);
+
+ }
+
+ /**
+ * Test checking the availability of the architecture instance according to the instance state.
+ * The architecture instance is available even in the STOPPED state.
+ */
+ @Test
+ public void testArchitectureServiceAvailability() {
+ String instanceName = instance1.getInstanceName();
+ // Check architecture of instance1
+ Architecture arch = ipojoHelper.getArchitectureByName(instanceName);
+ assertNotNull(arch);
+ assertEquals(ComponentInstance.VALID, arch.getInstanceDescription().getState());
+
+ // We stop the instance
+ instance1.stop();
+ arch = ipojoHelper.getArchitectureByName(instanceName);
+ assertNotNull(arch);
+ assertEquals(ComponentInstance.STOPPED, arch.getInstanceDescription().getState());
+
+ // Restart.
+ instance1.start();
+ arch = ipojoHelper.getArchitectureByName(instanceName);
+ assertNotNull(arch);
+ assertEquals(ComponentInstance.VALID, arch.getInstanceDescription().getState());
+
+ // Disposal
+ instance1.dispose();
+ arch = ipojoHelper.getArchitectureByName(instanceName);
+ 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-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBothProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBothProperties.java
new file mode 100644
index 0000000..07fb384
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBothProperties.java
@@ -0,0 +1,870 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestBothProperties extends Common {
+
+ ComponentInstance instance, instance2;
+
+ @Before
+ public void setUp() {
+ Factory fact = ipojoHelper.getFactory("CONFIG-BothConfigurableCheckService");
+ Properties props = new Properties();
+ props.put("instance.name", "under-test");
+ props.put("b", "1");
+ props.put("s", "1");
+ props.put("i", "1");
+ props.put("l", "1");
+ props.put("d", "1");
+ props.put("f", "1");
+ props.put("c", "a");
+ props.put("bool", "true");
+ props.put("bs", "{1,2,3}");
+ props.put("ss", "{1,2,3}");
+ props.put("is", "{1,2,3}");
+ props.put("ls", "{1,2,3}");
+ props.put("ds", "{1,2,3}");
+ props.put("fs", "{1,2,3}");
+ props.put("cs", "{a,b,c}");
+ props.put("bools", "{true,true,true}");
+ props.put("string", "foo");
+ props.put("strings", "{foo, bar, baz}");
+
+ try {
+ instance = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the under-test instance : " + e.getMessage());
+ }
+
+ try {
+ instance2 = fact.createComponentInstance(null);
+ } catch (Exception e) {
+ fail("Cannot create the under-test instance2 : " + e.getMessage());
+ }
+
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance2.dispose();
+ instance = null;
+ instance2 = null;
+ }
+
+ @Test
+ public void testConfigurationPrimitive() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"), 0);
+ assertEquals("Check f", f, new Float("1"), 0);
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+ Integer upb = (Integer) props.get("upb");
+ Integer ups = (Integer) props.get("ups");
+ Integer upi = (Integer) props.get("upi");
+ Integer upl = (Integer) props.get("upl");
+ Integer upd = (Integer) props.get("upd");
+ Integer upf = (Integer) props.get("upf");
+ Integer upc = (Integer) props.get("upc");
+ Integer upbool = (Integer) props.get("upbool");
+
+ assertEquals("Check upb", upb, new Integer(1));
+ assertEquals("Check ups", ups, new Integer(1));
+ assertEquals("Check upi", upi, new Integer(1));
+ assertEquals("Check upl", upl, new Integer(1));
+ assertEquals("Check upd", upd, new Integer(1));
+ assertEquals("Check upf", upf, new Integer(1));
+ assertEquals("Check upc", upc, new Integer(1));
+ assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"), 0);
+ assertEquals("2) Check f", f, new Float("2"), 0);
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ upb = (Integer) props.get("upb");
+ ups = (Integer) props.get("ups");
+ upi = (Integer) props.get("upi");
+ upl = (Integer) props.get("upl");
+ upd = (Integer) props.get("upd");
+ upf = (Integer) props.get("upf");
+ upc = (Integer) props.get("upc");
+ upbool = (Integer) props.get("upbool");
+
+ assertEquals("2) Check upb", upb, new Integer(2));
+ assertEquals("2) Check ups", ups, new Integer(2));
+ assertEquals("2) Check upi", upi, new Integer(2));
+ assertEquals("2) Check upl", upl, new Integer(2));
+ assertEquals("2) Check upd", upd, new Integer(2));
+ assertEquals("2) Check upf", upf, new Integer(2));
+ assertEquals("2) Check upc", upc, new Integer(2));
+ assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"), 0);
+ assertEquals("Check f", f, new Float("1"), 0);
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+ Integer upb = (Integer) props.get("upb");
+ Integer ups = (Integer) props.get("ups");
+ Integer upi = (Integer) props.get("upi");
+ Integer upl = (Integer) props.get("upl");
+ Integer upd = (Integer) props.get("upd");
+ Integer upf = (Integer) props.get("upf");
+ Integer upc = (Integer) props.get("upc");
+ Integer upbool = (Integer) props.get("upbool");
+
+ assertEquals("Check upb", upb, new Integer(1));
+ assertEquals("Check ups", ups, new Integer(1));
+ assertEquals("Check upi", upi, new Integer(1));
+ assertEquals("Check upl", upl, new Integer(1));
+ assertEquals("Check upd", upd, new Integer(1));
+ assertEquals("Check upf", upf, new Integer(1));
+ assertEquals("Check upc", upc, new Integer(1));
+ assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"), 0);
+ assertEquals("2) Check f", f, new Float("2"), 0);
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ upb = (Integer) props.get("upb");
+ ups = (Integer) props.get("ups");
+ upi = (Integer) props.get("upi");
+ upl = (Integer) props.get("upl");
+ upd = (Integer) props.get("upd");
+ upf = (Integer) props.get("upf");
+ upc = (Integer) props.get("upc");
+ upbool = (Integer) props.get("upbool");
+
+ assertEquals("2) Check upb", upb, new Integer(2));
+ assertEquals("2) Check ups", ups, new Integer(2));
+ assertEquals("2) Check upi", upi, new Integer(2));
+ assertEquals("2) Check upl", upl, new Integer(2));
+ assertEquals("2) Check upd", upd, new Integer(2));
+ assertEquals("2) Check upf", upf, new Integer(2));
+ assertEquals("2) Check upc", upc, new Integer(2));
+ assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1.0, 0);
+ assertEquals("Check d 1", d[1], 2.0, 0);
+ assertEquals("Check d 2", d[2], 3.0, 0);
+ assertEquals("Check f 0", f[0], 1.0, 0);
+ assertEquals("Check f 1", f[1], 2.0, 0);
+ assertEquals("Check f 2", f[2], 3.0, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+ Integer upb = (Integer) props.get("upbs");
+ Integer ups = (Integer) props.get("upss");
+ Integer upi = (Integer) props.get("upis");
+ Integer upl = (Integer) props.get("upls");
+ Integer upd = (Integer) props.get("upds");
+ Integer upf = (Integer) props.get("upfs");
+ Integer upc = (Integer) props.get("upcs");
+ Integer upbool = (Integer) props.get("upbools");
+
+ assertEquals("Check upb", upb, new Integer(1));
+ assertEquals("Check ups", ups, new Integer(1));
+ assertEquals("Check upi", upi, new Integer(1));
+ assertEquals("Check upl", upl, new Integer(1));
+ assertEquals("Check upd", upd, new Integer(1));
+ assertEquals("Check upf", upf, new Integer(1));
+ assertEquals("Check upc", upc, new Integer(1));
+ assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3.0, 0);
+ assertEquals("2) Check d 1", d[1], 2.0, 0);
+ assertEquals("2) Check d 2", d[2], 1.0, 0);
+ assertEquals("2) Check f 0", f[0], 3.0, 0);
+ assertEquals("2) Check f 1", f[1], 2.0, 0);
+ assertEquals("2) Check f 2", f[2], 1.0, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ upb = (Integer) props.get("upbs");
+ ups = (Integer) props.get("upss");
+ upi = (Integer) props.get("upis");
+ upl = (Integer) props.get("upls");
+ upd = (Integer) props.get("upds");
+ upf = (Integer) props.get("upfs");
+ upc = (Integer) props.get("upcs");
+ upbool = (Integer) props.get("upbools");
+
+ assertEquals("2) Check upb", upb, new Integer(2));
+ assertEquals("2) Check ups", ups, new Integer(2));
+ assertEquals("2) Check upi", upi, new Integer(2));
+ assertEquals("2) Check upl", upl, new Integer(2));
+ assertEquals("2) Check upd", upd, new Integer(2));
+ assertEquals("2) Check upf", upf, new Integer(2));
+ assertEquals("2) Check upc", upc, new Integer(2));
+ assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1.0, 0);
+ assertEquals("Check d 1", d[1], 2.0, 0);
+ assertEquals("Check d 2", d[2], 3.0, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+ Integer upb = (Integer) props.get("upbs");
+ Integer ups = (Integer) props.get("upss");
+ Integer upi = (Integer) props.get("upis");
+ Integer upl = (Integer) props.get("upls");
+ Integer upd = (Integer) props.get("upds");
+ Integer upf = (Integer) props.get("upfs");
+ Integer upc = (Integer) props.get("upcs");
+ Integer upbool = (Integer) props.get("upbools");
+
+ assertEquals("Check upb", upb, new Integer(1));
+ assertEquals("Check ups", ups, new Integer(1));
+ assertEquals("Check upi", upi, new Integer(1));
+ assertEquals("Check upl", upl, new Integer(1));
+ assertEquals("Check upd", upd, new Integer(1));
+ assertEquals("Check upf", upf, new Integer(1));
+ assertEquals("Check upc", upc, new Integer(1));
+ assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3.0, 0);
+ assertEquals("2) Check d 1", d[1], 2.0, 0);
+ assertEquals("2) Check d 2", d[2], 1.0, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ upb = (Integer) props.get("upbs");
+ ups = (Integer) props.get("upss");
+ upi = (Integer) props.get("upis");
+ upl = (Integer) props.get("upls");
+ upd = (Integer) props.get("upds");
+ upf = (Integer) props.get("upfs");
+ upc = (Integer) props.get("upcs");
+ upbool = (Integer) props.get("upbools");
+
+ assertEquals("2) Check upb", upb, new Integer(2));
+ assertEquals("2) Check ups", ups, new Integer(2));
+ assertEquals("2) Check upi", upi, new Integer(2));
+ assertEquals("2) Check upl", upl, new Integer(2));
+ assertEquals("2) Check upd", upd, new Integer(2));
+ assertEquals("2) Check upf", upf, new Integer(2));
+ assertEquals("2) Check upc", upc, new Integer(2));
+ assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationObj() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+ Integer upString = (Integer) props.get("upstring");
+ Integer upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("Check upString", upString, new Integer(1));
+ assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+ upString = (Integer) props.get("upstring");
+ upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("2) Check upstring", upString, new Integer(2));
+ assertEquals("2) Check upstrings", upStrings, new Integer(2));
+ }
+
+ @Test
+ public void testConfigurationObjString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+ Integer upString = (Integer) props.get("upstring");
+ Integer upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("Check upString", upString, new Integer(1));
+ assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+ upString = (Integer) props.get("upstring");
+ upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("2) Check upstring", upString, new Integer(2));
+ assertEquals("2) Check upstrings", upStrings, new Integer(2));
+ }
+
+ private void reconfigure(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", new Byte("2"));
+ props2.put("s", new Short("2"));
+ props2.put("i", new Integer("2"));
+ props2.put("l", new Long("2"));
+ props2.put("d", new Double("2"));
+ props2.put("f", new Float("2"));
+ props2.put("c", new Character('b'));
+ props2.put("bool", new Boolean(false));
+ props2.put("bs", new byte[]{(byte) 3, (byte) 2, (byte) 1});
+ props2.put("ss", new short[]{(short) 3, (short) 2, (short) 1});
+ props2.put("is", new int[]{3, 2, 1});
+ props2.put("ls", new long[]{3, 2, 1});
+ props2.put("ds", new double[]{3, 2, 1});
+ props2.put("fs", new float[]{3, 2, 1});
+ props2.put("cs", new char[]{'c', 'b', 'a'});
+ props2.put("bools", new boolean[]{false, false, false});
+ props2.put("string", "bar");
+ props2.put("strings", new String[]{"baz", "bar", "foo"});
+
+ ci.reconfigure(props2);
+ }
+
+ private void reconfigureString(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", "2");
+ props2.put("s", "2");
+ props2.put("i", "2");
+ props2.put("l", "2");
+ props2.put("d", "2");
+ props2.put("f", "2");
+ props2.put("c", "b");
+ props2.put("bool", "false");
+ props2.put("bs", "{3, 2,1}");
+ props2.put("ss", "{3, 2,1}");
+ props2.put("is", "{3, 2,1}");
+ props2.put("ls", "{3, 2,1}");
+ props2.put("ds", "{3, 2,1}");
+ props2.put("fs", "{3, 2,1}");
+ props2.put("cs", "{c, b , a}");
+ props2.put("bools", "{false,false,false}");
+ props2.put("string", "bar");
+ props2.put("strings", "{baz, bar, foo}");
+
+ ci.reconfigure(props2);
+ }
+
+ @Test
+ public void testConfigurationPrimitiveNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("0"));
+ assertEquals("Check s", s, new Short("0"));
+ assertEquals("Check i", i, new Integer("0"));
+ assertEquals("Check l", l, new Long("0"));
+ assertEquals("Check d", d, new Double("0"), 0);
+ assertEquals("Check f", f, new Float("0"), 0);
+ assertEquals("Check c", c, new Character((char) 0));
+ assertEquals("Check bool", bool, new Boolean(false));
+
+ Integer upb = (Integer) props.get("upb");
+ Integer ups = (Integer) props.get("ups");
+ Integer upi = (Integer) props.get("upi");
+ Integer upl = (Integer) props.get("upl");
+ Integer upd = (Integer) props.get("upd");
+ Integer upf = (Integer) props.get("upf");
+ Integer upc = (Integer) props.get("upc");
+ Integer upbool = (Integer) props.get("upbool");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"), 0);
+ assertEquals("2) Check f", f, new Float("2"), 0);
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ upb = (Integer) props.get("upb");
+ ups = (Integer) props.get("ups");
+ upi = (Integer) props.get("upi");
+ upl = (Integer) props.get("upl");
+ upd = (Integer) props.get("upd");
+ upf = (Integer) props.get("upf");
+ upc = (Integer) props.get("upc");
+ upbool = (Integer) props.get("upbool");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ //assertEquals("2) Check upbool", upbool, new Integer(1)); // TODO Why 0 ???
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertNull("Check b nullity", b);
+ assertNull("Check s nullity", s);
+ assertNull("Check i nullity", i);
+ assertNull("Check l nullity", l);
+ assertNull("Check d nullity", d);
+ assertNull("Check f nullity", f);
+ assertNull("Check c nullity", c);
+ assertNull("Check bool nullity", bool);
+
+ Integer upb = (Integer) props.get("upbs");
+ Integer ups = (Integer) props.get("upss");
+ Integer upi = (Integer) props.get("upis");
+ Integer upl = (Integer) props.get("upls");
+ Integer upd = (Integer) props.get("upds");
+ Integer upf = (Integer) props.get("upfs");
+ Integer upc = (Integer) props.get("upcs");
+ Integer upbool = (Integer) props.get("upbools");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3.0, 0);
+ assertEquals("2) Check d 1", d[1], 2.0, 0);
+ assertEquals("2) Check d 2", d[2], 1.0, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ upb = (Integer) props.get("upbs");
+ ups = (Integer) props.get("upss");
+ upi = (Integer) props.get("upis");
+ upl = (Integer) props.get("upls");
+ upd = (Integer) props.get("upds");
+ upf = (Integer) props.get("upfs");
+ upc = (Integer) props.get("upcs");
+ upbool = (Integer) props.get("upbools");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ assertEquals("2) Check upbool", upbool, new Integer(1));
+
+ }
+
+ @Test
+ public void testConfigurationObjNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, null);
+ assertEquals("Check strings", ss, null);
+
+
+ Integer upString = (Integer) props.get("upstring");
+ Integer upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("Check upString", upString, new Integer(0));
+ assertEquals("Check upStrings", upStrings, new Integer(0));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+ upString = (Integer) props.get("upstring");
+ upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("2) Check upstring", upString, new Integer(1));
+ assertEquals("2) Check upstrings", upStrings, new Integer(1));
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexProperties.java
new file mode 100644
index 0000000..782915d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComplexProperties.java
@@ -0,0 +1,234 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+public class TestComplexProperties extends Common {
+
+
+ private ServiceReference m_ref;
+ private CheckService m_check;
+
+ @Before
+ public void setUp() {
+ m_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "complex");
+ assertNotNull("Complex service availability", m_ref);
+ m_check = (CheckService) osgiHelper.getRawServiceObject(m_ref);
+ }
+
+ @After
+ public void tearDown() {
+ m_check = null;
+
+ }
+
+ @Test
+ public void testArray() {
+ String[] array = (String[]) m_check.getProps().get("array");
+ assertEquals("Array size", 2, array.length);
+ assertEquals("Array[0]", "a", array[0]);
+ assertEquals("Array[1]", "b", array[1]);
+ }
+
+ @Test
+ public void testList() {
+ List list = (List) m_check.getProps().get("list");
+ assertEquals("List size", 2, list.size());
+ assertEquals("List[0]", "a", list.get(0));
+ assertEquals("List[1]", "b", list.get(1));
+ }
+
+ @Test
+ public void testMap() {
+ Map map = (Map) m_check.getProps().get("map");
+ assertEquals("Map size", 2, map.size());
+ assertEquals("Map[a]", "a", map.get("a"));
+ assertEquals("Map[b]", "b", map.get("b"));
+ }
+
+ @Test
+ public void testDictionary() {
+ Dictionary dict = (Dictionary) m_check.getProps().get("dict");
+ assertEquals("Map size", 2, dict.size());
+ assertEquals("Map[a]", "a", dict.get("a"));
+ assertEquals("Map[b]", "b", dict.get("b"));
+ }
+
+ @Test
+ public void testComplexArray() {
+ Object[] array = (Object[]) m_check.getProps().get("complex-array");
+ assertEquals("Array size", 2, array.length);
+ assertTrue("Array[0] type", array[0] instanceof List);
+ assertTrue("Array[1] type", array[1] instanceof List);
+ List list = (List) array[0];
+ assertEquals("List size", 2, list.size());
+ assertEquals("List[0]", "a", list.get(0));
+ assertEquals("List[1]", "b", list.get(1));
+ list = (List) array[1];
+ assertEquals("List size - 2", 2, list.size());
+ assertEquals("List[0] - 2", "c", list.get(0));
+ assertEquals("List[1] - 2", "d", list.get(1));
+ }
+
+ @Test
+ public void testComplexList() {
+ List list = (List) m_check.getProps().get("complex-list");
+ assertEquals("List size", 2, list.size());
+ assertTrue("List[0] type", list.get(0) instanceof List);
+ assertTrue("List[1] type", list.get(1) instanceof List);
+ List list1 = (List) list.get(0);
+ assertEquals("List size - 1", 2, list1.size());
+ assertEquals("List[0] - 1", "a", list1.get(0));
+ assertEquals("List[1] - 1", "b", list1.get(1));
+ list1 = (List) list.get(1);
+ assertEquals("List size - 2", 2, list1.size());
+ assertEquals("List[0] - 2", "c", list1.get(0));
+ assertEquals("List[1] - 2", "d", list1.get(1));
+ }
+
+ @Test
+ public void testComplexMap() {
+ Map map = (Map) m_check.getProps().get("complex-map");
+ assertEquals("List size", 2, map.size());
+ assertTrue("List[0] type", map.get("a") instanceof List);
+ assertTrue("List[1] type", map.get("b") instanceof List);
+ List list = (List) map.get("a");
+ assertEquals("List size - 1", 2, list.size());
+ assertEquals("List[0] - 1", "a", list.get(0));
+ assertEquals("List[1] - 1", "b", list.get(1));
+ list = (List) map.get("b");
+ assertEquals("List size - 2", 2, list.size());
+ assertEquals("List[0] - 2", "c", list.get(0));
+ assertEquals("List[1] - 2", "d", list.get(1));
+ }
+
+ @Test
+ public void testServiceArray() {
+ String[] array = (String[]) m_ref.getProperty("array");
+ assertEquals("Array size", 2, array.length);
+ assertEquals("Array[0]", "a", array[0]);
+ assertEquals("Array[1]", "b", array[1]);
+ }
+
+ @Test
+ public void testServiceList() {
+ List list = (List) m_ref.getProperty("list");
+ assertEquals("List size", 2, list.size());
+ assertEquals("List[0]", "a", list.get(0));
+ assertEquals("List[1]", "b", list.get(1));
+ }
+
+ @Test
+ public void testServiceMap() {
+ Map map = (Map) m_ref.getProperty("map");
+ assertEquals("Map size", 2, map.size());
+ assertEquals("Map[a]", "a", map.get("a"));
+ assertEquals("Map[b]", "b", map.get("b"));
+ }
+
+ @Test
+ public void testServiceDictionary() {
+ Dictionary dict = (Dictionary) m_ref.getProperty("dict");
+ assertEquals("Map size", 2, dict.size());
+ assertEquals("Map[a]", "a", dict.get("a"));
+ assertEquals("Map[b]", "b", dict.get("b"));
+ }
+
+ @Test
+ public void testServiceComplexArray() {
+ Object[] array = (Object[]) m_ref.getProperty("complex-array");
+ assertEquals("Array size", 2, array.length);
+ assertTrue("Array[0] type", array[0] instanceof List);
+ assertTrue("Array[1] type", array[1] instanceof List);
+ List list = (List) array[0];
+ assertEquals("List size", 2, list.size());
+ assertEquals("List[0]", "a", list.get(0));
+ assertEquals("List[1]", "b", list.get(1));
+ list = (List) array[1];
+ assertEquals("List size - 2", 2, list.size());
+ assertEquals("List[0] - 2", "c", list.get(0));
+ assertEquals("List[1] - 2", "d", list.get(1));
+ }
+
+ @Test
+ public void testServiceComplexList() {
+ List list = (List) m_ref.getProperty("complex-list");
+ assertEquals("List size", 2, list.size());
+ assertTrue("List[0] type", list.get(0) instanceof List);
+ assertTrue("List[1] type", list.get(1) instanceof List);
+ List list1 = (List) list.get(0);
+ assertEquals("List size - 1", 2, list1.size());
+ assertEquals("List[0] - 1", "a", list1.get(0));
+ assertEquals("List[1] - 1", "b", list1.get(1));
+ list1 = (List) list.get(1);
+ assertEquals("List size - 2", 2, list1.size());
+ assertEquals("List[0] - 2", "c", list1.get(0));
+ assertEquals("List[1] - 2", "d", list1.get(1));
+ }
+
+ @Test
+ public void testServiceComplexMap() {
+ Map map = (Map) m_ref.getProperty("complex-map");
+ assertEquals("List size", 2, map.size());
+ assertTrue("List[0] type", map.get("a") instanceof List);
+ assertTrue("List[1] type", map.get("b") instanceof List);
+ List list = (List) map.get("a");
+ assertEquals("List size - 1", 2, list.size());
+ assertEquals("List[0] - 1", "a", list.get(0));
+ assertEquals("List[1] - 1", "b", list.get(1));
+ list = (List) map.get("b");
+ assertEquals("List size - 2", 2, list.size());
+ assertEquals("List[0] - 2", "c", list.get(0));
+ assertEquals("List[1] - 2", "d", list.get(1));
+ }
+
+ @Test
+ public void testServiceEmptyArray() {
+ String[] array = (String[]) m_ref.getProperty("empty-array");
+ assertEquals("Array size", 0, array.length);
+ }
+
+ @Test
+ public void testServiceEmptyList() {
+ List list = (List) m_ref.getProperty("empty-list");
+ assertEquals("List size", 0, list.size());
+ }
+
+ @Test
+ public void testServiceEmptyMap() {
+ Map map = (Map) m_ref.getProperty("empty-map");
+ assertEquals("Map size", 0, map.size());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConstructorInjectionOfProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConstructorInjectionOfProperties.java
new file mode 100644
index 0000000..b153268
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConstructorInjectionOfProperties.java
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+
+public class TestConstructorInjectionOfProperties extends Common {
+
+
+ @Test
+ public void testInjectionOfNamedProperty() {
+ Dictionary<String, String> conf = new Hashtable<String, String>();
+ conf.put("message", "message");
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.constructor.CheckServiceProviderWithNamedProperty", conf);
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() +")",
+ 1000);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertEquals(cs.getProps().getProperty("message"), "message");
+ }
+
+ @Test
+ public void testInjectionOfUnnamedProperty() {
+ Dictionary<String, String> conf = new Hashtable<String, String>();
+ conf.put("message", "message");
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.constructor.CheckServiceProviderWithUnnamedProperty", conf);
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() +")",
+ 1000);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertEquals(cs.getProps().getProperty("message"), "message");
+ }
+
+ @Test
+ public void testInjectionOfPropertyWithDefaultValue() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.constructor.CheckServiceProviderWithDefaultValueProperty");
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() +")",
+ 1000);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertEquals(cs.getProps().getProperty("message"), "message");
+ }
+
+ @Test
+ public void testInjectionOfTwoProperties() {
+ Dictionary<String, String> conf = new Hashtable<String, String>();
+ conf.put("message", "message");
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.constructor.CheckServiceProviderWithTwoProperties", conf);
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() +")",
+ 1000);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertEquals(cs.getProps().getProperty("message"), "message");
+ assertEquals(cs.getProps().getProperty("product"), "ipojo");
+ }
+
+ @Test
+ public void testInjectionOfAPropertyAndBundleContext() {
+ Dictionary<String, String> conf = new Hashtable<String, String>();
+ conf.put("message", "message");
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.constructor.CheckServiceProviderWithBundleContextAndProperty", conf);
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() +")",
+ 1000);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertEquals(cs.getProps().getProperty("message"), "message");
+ assertNotNull(cs.getProps().get("context"));
+ assertTrue(cs.getProps().get("context") instanceof BundleContext);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicallyConfigurablePropertiesUsingConfigAdmin.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicallyConfigurablePropertiesUsingConfigAdmin.java
new file mode 100644
index 0000000..6f78e6c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicallyConfigurablePropertiesUsingConfigAdmin.java
@@ -0,0 +1,399 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * iPOJO does not expose the ManagedServiceFactory anymore, we must use the configuration admin.
+ */
+public class TestDynamicallyConfigurablePropertiesUsingConfigAdmin extends Common {
+
+ ComponentInstance instance, instance2;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-3";
+
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance-r");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ instance = ipojoHelper.createComponentInstance(type, p1);
+
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance2");
+
+ instance2 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance2.dispose();
+ instance2 = null;
+ instance = null;
+ }
+
+ @Test
+ public void testStatic() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", 2);
+ conf.put("foo", "foo");
+ conf.put("instance.name", instance.getInstanceName());
+
+ configuration.update(conf);
+
+ // Asynchronous dispatching of the configuration
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+ }
+
+ @Test
+ public void testStaticNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", 2);
+ conf.put("foo", "foo");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, 2);
+ assertEquals("Check baz equality -2", bazP, "zab");
+ }
+
+ @Test
+ public void testDynamic() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", 0);
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ }
+
+ @Test
+ public void testDynamicNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", 0);
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, 0);
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, 0);
+
+ osgiHelper.getContext().ungetService(fooRef);
+ }
+
+ @Test
+ public void testDynamicString() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(),
+ instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", "0");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ }
+
+ @Test
+ public void testPropagation() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "foo");
+ conf.put("bar", 2);
+ conf.put("propagated1", "propagated");
+ conf.put("propagated2", 1);
+ conf.put(".notpropagated", "xxx");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ System.out.println(instance.getInstanceDescription().getDescription());
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertNotNull("Check the propagated1 existence", fooRef.getProperty("propagated1"));
+ String prop1 = (String) fooRef.getProperty("propagated1");
+ assertNotNull("Check the propagated2 existence", fooRef.getProperty("propagated2"));
+ Integer prop2 = (Integer) fooRef.getProperty("propagated2");
+ assertNull("Check the not propagated non-existence", fooRef.getProperty(".notpropagated"));
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "zab");
+ assertEquals("Check propagated1 equality", prop1, "propagated");
+ assertEquals("Check propagated2 equality", prop2, new Integer(1));
+ }
+
+ @Test
+ public void testPropagationNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "foo");
+ conf.put("bar", new Integer(2));
+ conf.put("propagated1", "propagated");
+ conf.put("propagated2", new Integer(1));
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertNotNull("Check the propagated1 existency", fooRef.getProperty("propagated1"));
+ String prop1 = (String) fooRef.getProperty("propagated1");
+ assertNotNull("Check the propagated2 existency", fooRef.getProperty("propagated2"));
+ Integer prop2 = (Integer) fooRef.getProperty("propagated2");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "zab");
+ assertEquals("Check propagated1 equality", prop1, "propagated");
+ assertEquals("Check propagated2 equality", prop2, new Integer(1));
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFieldProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFieldProperties.java
new file mode 100644
index 0000000..b3e3380
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFieldProperties.java
@@ -0,0 +1,768 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+
+public class TestFieldProperties extends Common {
+
+ ComponentInstance instance;
+ ComponentInstance instance2;
+
+ @Before
+ public void setUp() {
+ osgiHelper = new OSGiHelper(bc);
+ ipojoHelper = new IPOJOHelper(bc);
+ Factory fact = ipojoHelper.getFactory("CONFIG-FieldConfigurableCheckService");
+ Properties props = new Properties();
+ props.put("instance.name", "under-test");
+ props.put("b", "1");
+ props.put("s", "1");
+ props.put("i", "1");
+ props.put("l", "1");
+ props.put("d", "1");
+ props.put("f", "1");
+ props.put("c", "a");
+ props.put("bool", "true");
+ props.put("bs", "{1,2,3}");
+ props.put("ss", "{1,2,3}");
+ props.put("is", "{1,2,3}");
+ props.put("ls", "{1,2,3}");
+ props.put("ds", "{1,2,3}");
+ props.put("fs", "{1,2,3}");
+ props.put("cs", "{a,b,c}");
+ props.put("bools", "{true,true,true}");
+ props.put("string", "foo");
+ props.put("strings", "{foo, bar, baz}");
+
+ try {
+ instance = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the under-test instance : " + e.getMessage());
+ }
+
+ try {
+ instance2 = fact.createComponentInstance(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot create the instance : " + e.getMessage());
+
+ }
+
+
+ }
+
+ @After
+ public void tearDown() {
+ ipojoHelper.dispose();
+ osgiHelper.dispose();
+ instance.dispose();
+ instance2.dispose();
+ instance = null;
+ instance2 = null;
+ }
+
+ @Test
+ public void testConfigurationPrimitive() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("0"));
+ assertEquals("Check s", s, new Short("0"));
+ assertEquals("Check i", i, new Integer("0"));
+ assertEquals("Check l", l, new Long("0"));
+ assertEquals("Check d", d, new Double("0"));
+ assertEquals("Check f", f, new Float("0"));
+ assertEquals("Check c", c, new Character((char) 0));
+ assertEquals("Check bool", bool, new Boolean(false));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("0"));
+ assertEquals("Check s", s, new Short("0"));
+ assertEquals("Check i", i, new Integer("0"));
+ assertEquals("Check l", l, new Long("0"));
+ assertEquals("Check d", d, new Double("0"));
+ assertEquals("Check f", f, new Float("0"));
+ assertEquals("Check c", c, new Character((char) 0));
+ assertEquals("Check bool", bool, new Boolean(false));
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertNull("Check b nullity", b);
+ assertNull("Check s nullity", s);
+ assertNull("Check i nullity", i);
+ assertNull("Check l nullity", l);
+ assertNull("Check d nullity", d);
+ assertNull("Check f nullity", f);
+ assertNull("Check c nullity", c);
+ assertNull("Check bool nullity", bool);
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertNull("Check b nullity", b);
+ assertNull("Check s nullity", s);
+ assertNull("Check i nullity", i);
+ assertNull("Check l nullity", l);
+ assertNull("Check d nullity", d);
+ assertNull("Check f nullity", f);
+ assertNull("Check c nullity", c);
+ assertNull("Check bool nullity", bool);
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ }
+
+ @Test
+ public void testConfigurationObj() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+ }
+
+ @Test
+ public void testConfigurationObjNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, null);
+ assertEquals("Check strings", ss, null);
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+ }
+
+ @Test
+ public void testConfigurationObjString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+ }
+
+ @Test
+ public void testConfigurationObjStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, null);
+ assertEquals("Check strings", ss, null);
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("TeosgiHelper.getRawServiceObjectty", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+ }
+
+ private void reconfigure(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", new Byte("2"));
+ props2.put("s", new Short("2"));
+ props2.put("i", new Integer("2"));
+ props2.put("l", new Long("2"));
+ props2.put("d", new Double("2"));
+ props2.put("f", new Float("2"));
+ props2.put("c", new Character('b'));
+ props2.put("bool", new Boolean(false));
+ props2.put("bs", new byte[]{(byte) 3, (byte) 2, (byte) 1});
+ props2.put("ss", new short[]{(short) 3, (short) 2, (short) 1});
+ props2.put("is", new int[]{3, 2, 1});
+ props2.put("ls", new long[]{3, 2, 1});
+ props2.put("ds", new double[]{3, 2, 1});
+ props2.put("fs", new float[]{3, 2, 1});
+ props2.put("cs", new char[]{'c', 'b', 'a'});
+ props2.put("bools", new boolean[]{false, false, false});
+ props2.put("string", "bar");
+ props2.put("strings", new String[]{"baz", "bar", "foo"});
+
+ ci.reconfigure(props2);
+ }
+
+ private void reconfigureString(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", "2");
+ props2.put("s", "2");
+ props2.put("i", "2");
+ props2.put("l", "2");
+ props2.put("d", "2");
+ props2.put("f", "2");
+ props2.put("c", "b");
+ props2.put("bool", "false");
+ props2.put("bs", "{3, 2,1}");
+ props2.put("ss", "{3, 2,1}");
+ props2.put("is", "{3, 2,1}");
+ props2.put("ls", "{3, 2,1}");
+ props2.put("ds", "{3, 2,1}");
+ props2.put("fs", "{3, 2,1}");
+ props2.put("cs", "{c, b , a}");
+ props2.put("bools", "{false,false,false}");
+ props2.put("string", "bar");
+ props2.put("strings", "{baz, bar, foo}");
+
+ ci.reconfigure(props2);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java
new file mode 100644
index 0000000..d420fa8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java
@@ -0,0 +1,205 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandlerDescription;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationListener;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test that the ConfigurationHandler calls the ConfigurationListeners when watched instance is reconfigured.
+ */
+public class TestListeners extends Common {
+
+ /**
+ * The number of reconfigurations, incremented by the {@code CountingListener}s.
+ */
+ int updates = 0;
+
+ /**
+ * The {@code instance} arguments received by the {@code AppendingListener}s.
+ */
+ List<ComponentInstance> instances = new ArrayList<ComponentInstance>();
+
+ /**
+ * The {@code configuration} arguments received by the {@code AppendingListener}s.
+ */
+ List<Map<String, Object>> configs = new ArrayList<Map<String, Object>>();
+
+ /**
+ * The tested component instance.
+ */
+ ComponentInstance fooProvider;
+
+ /**
+ * The configuration handler description of the tested component instance.
+ */
+ ConfigurationHandlerDescription fooConfig;
+
+ /**
+ * The service provided by the tested component instance.
+ */
+ FooService foo;
+
+ @Before
+ public void setUp() {
+ Properties p = new Properties();
+ p.put("instance.name", "FooProvider-42");
+ p.put("int", 4);
+ p.put("boolean", false);
+ p.put("string", "bar");
+ p.put("strAProp", new String[]{"bar", "foo"});
+ p.put("intAProp", new int[]{1, 2, 3});
+ fooProvider = ipojoHelper.createComponentInstance("CONFIG-FooProviderType-ConfUpdated", p);
+ fooConfig = (ConfigurationHandlerDescription) fooProvider.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:properties");
+
+ // Get the service
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-42");
+ foo = (FooService) osgiHelper.getRawServiceObject(ref);
+ }
+
+ @After
+ public void tearDown() {
+ fooConfig = null;
+ fooProvider.dispose();
+ fooProvider = null;
+ }
+
+ /**
+ * A ConfigurationListener that just count its calls.
+ */
+ private class CountingListener implements ConfigurationListener {
+ public void configurationChanged(ComponentInstance instance, Map<String, Object> configuration) {
+ updates++;
+ }
+ }
+
+ /**
+ * A ConfigurationListener that just fails.
+ * <p>
+ * Used to ensure that a failing listener does not prevent the following listeners to be called.
+ * </p>
+ */
+ private class ThrowingListener implements ConfigurationListener {
+ public void configurationChanged(ComponentInstance instance, Map<String, Object> configuration) {
+ throw new RuntimeException("I'm bad");
+ }
+ }
+
+ /**
+ * A ConfigurationListener that just appends its arguments.
+ */
+ private class AppendingListener implements ConfigurationListener {
+ public void configurationChanged(ComponentInstance instance, Map<String, Object> configuration) {
+ instances.add(instance);
+ configs.add(configuration);
+ }
+ }
+
+ /**
+ * Test that the listeners registered on the tested instance are called when the instance is reconfigured.
+ */
+ @Test
+ public void testConfigurationListener() {
+ // Register listeners
+ ConfigurationListener l1 = new CountingListener();
+ fooConfig.addListener(l1);
+ ConfigurationListener l2 = new ThrowingListener();
+ fooConfig.addListener(l2);
+ ConfigurationListener l3 = new AppendingListener();
+ fooConfig.addListener(l3);
+
+ // Trigger a manual reconfiguration
+ Hashtable<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("int", 40);
+ conf.put("boolean", true);
+ conf.put("string", "saloon");
+ conf.put("strAProp", new String[]{"bar", "bad"});
+ conf.put("intAProp", new int[]{21, 22, 23});
+ fooProvider.reconfigure(conf);
+
+ // Check the listeners has been called + check the arguments.
+ assertEquals(1, updates);
+
+ assertEquals(1, instances.size());
+ assertSame(fooProvider, instances.get(0));
+
+ assertEquals(1, configs.size());
+ Map<String, Object> configMap = configs.get(0);
+ assertEquals(5, configMap.size());
+ assertEquals(40, configMap.get("int"));
+ assertEquals(true, configMap.get("boolean"));
+ assertEquals("saloon", configMap.get("string"));
+ assertArrayEquals(new String[]{"bar", "bad"}, (String[]) configMap.get("strAProp"));
+ assertArrayEquals(new int[]{21, 22, 23}, (int[]) configMap.get("intAProp"));
+
+ // Trigger a POJO internal "reconfiguration".
+ // It should not trigger any reconfiguration event.
+ foo.foo();
+
+ // Check nothing has changed in the listeners
+ assertEquals(1, updates);
+ assertEquals(1, instances.size());
+ assertEquals(1, configs.size());
+
+ // Unregister the listeners
+ fooConfig.removeListener(l1);
+ fooConfig.removeListener(l2);
+ fooConfig.removeListener(l3);
+
+ // Trigger a manual reconfiguration
+ conf.put("int", 40);
+ conf.put("boolean", true);
+ conf.put("string", "saloon");
+ conf.put("strAProp", new String[]{"bar", "bad"});
+ conf.put("intAProp", new int[]{21, 22, 23});
+ fooProvider.reconfigure(conf);
+
+ // Check nothing has changed in the listeners, since they are all removed
+ assertEquals(1, updates);
+ assertEquals(1, instances.size());
+ assertEquals(1, configs.size());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNullProvidedServiceListener() {
+ // Should fail!
+ fooConfig.addListener(null);
+ }
+
+ /**
+ * This test was initially expecting a NoSuchElementException, in 1.11.2, we changed the method to ignore missing
+ * listeners.
+ */
+ @Test
+ public void testRemoveNonexistentProvidedServiceListener() {
+ fooConfig.removeListener(new ThrowingListener());
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceConfigurableProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceConfigurableProperties.java
new file mode 100644
index 0000000..6965fa6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManagedServiceConfigurableProperties.java
@@ -0,0 +1,618 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+
+public class TestManagedServiceConfigurableProperties extends Common {
+
+ /**
+ * Instance where the ManagedServicePID is provided by the component type.
+ */
+ ComponentInstance instance1;
+ /**
+ * Instance where the ManagedServicePID is provided by the instance.
+ */
+ ComponentInstance instance2;
+ /**
+ * Instance without configuration.
+ */
+ ComponentInstance instance3;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-4";
+ Hashtable<String, String> p = new Hashtable<String, String>();
+ p.put("instance.name", "instance");
+ p.put("foo", "foo");
+ p.put("bar", "2");
+ p.put("baz", "baz");
+ instance1 = ipojoHelper.createComponentInstance(type, p);
+ assertEquals("instance1 created", ComponentInstance.VALID, instance1.getState());
+
+ type = "CONFIG-FooProviderType-3";
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance-2");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ p1.put("managed.service.pid", "instance");
+ instance2 = ipojoHelper.createComponentInstance(type, p1);
+
+ type = "CONFIG-FooProviderType-3";
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance-3");
+ p2.put("managed.service.pid", "instance-3");
+ instance3 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ }
+
+ @Test
+ public void testStaticInstance1() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(
+ ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testStaticInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance");
+ assertNotNull("Check ManagedService availability", msRef);
+
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testStaticInstance3() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ // No values ... no properties.
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance-3");
+ assertNotNull("Check ManagedService availability", msRef);
+
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testDynamicInstance1() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testDynamicInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testDynamicInstance3() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ // No values ... no properties.
+ assertEquals("Check foo equality", fooP, null);
+ assertEquals("Check bar equality", barP, null);
+ assertEquals("Check baz equality", bazP, null);
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testDynamicStringInstance1() {
+ assertEquals("Check instance1 state", ComponentInstance.VALID, instance1.getState());
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality - 1", fooP, "foo");
+ assertEquals("Check bar equality - 1", barP, new Integer(2));
+ assertEquals("Check baz equality - 1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedService availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", "0");
+ assertEquals("Check instance1 state (2)", ComponentInstance.VALID, instance1.getState());
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+
+ PrimitiveHandler ph = (PrimitiveHandler) ms;
+ assertSame("Check the correct instance", ph.getInstanceManager(), instance1);
+
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+ assertEquals("Check instance1 state (3)", ComponentInstance.VALID, instance1.getState());
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality - 2", fooP, "oof");
+ assertEquals("Check bar equality - 2", barP, new Integer(0));
+ assertEquals("Check baz equality - 2", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testDynamicStringInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance");
+ assertNotNull("Check ManagedService availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", "0");
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getContext().getService(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ osgiHelper.getContext().ungetService(fooRef);
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testPropagationInstance1() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedService availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "foo");
+ conf.put("bar", new Integer(2));
+ conf.put("propagated1", "propagated");
+ conf.put("propagated2", new Integer(1));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertNotNull("Check the propagated1 existency", fooRef.getProperty("propagated1"));
+ String prop1 = (String) fooRef.getProperty("propagated1");
+ assertNotNull("Check the propagated2 existency", fooRef.getProperty("propagated2"));
+ Integer prop2 = (Integer) fooRef.getProperty("propagated2");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "zab");
+ assertEquals("Check propagated1 equality", prop1, "propagated");
+ assertEquals("Check propagated2 equality", prop2, new Integer(1));
+
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testPropagationInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance");
+ assertNotNull("Check ManagedService availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "foo");
+ conf.put("bar", new Integer(2));
+ conf.put("propagated1", "propagated");
+ conf.put("propagated2", new Integer(1));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertNotNull("Check the propagated1 existency", fooRef.getProperty("propagated1"));
+ String prop1 = (String) fooRef.getProperty("propagated1");
+ assertNotNull("Check the propagated2 existency", fooRef.getProperty("propagated2"));
+ Integer prop2 = (Integer) fooRef.getProperty("propagated2");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "zab");
+ assertEquals("Check propagated1 equality", prop1, "propagated");
+ assertEquals("Check propagated2 equality", prop2, new Integer(1));
+
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+ @Test
+ public void testPropagationInstance3() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, null);
+ assertEquals("Check bar equality", barP, null);
+ assertEquals("Check baz equality", bazP, null);
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instance-3");
+ assertNotNull("Check ManagedService availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "foo");
+ conf.put("bar", new Integer(2));
+ conf.put("propagated1", "propagated");
+ conf.put("propagated2", new Integer(1));
+ ManagedService ms = (ManagedService) osgiHelper.getContext().getService(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance3.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertNotNull("Check the propagated1 existency", fooRef.getProperty("propagated1"));
+ String prop1 = (String) fooRef.getProperty("propagated1");
+ assertNotNull("Check the propagated2 existency", fooRef.getProperty("propagated2"));
+ Integer prop2 = (Integer) fooRef.getProperty("propagated2");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "zab");
+ assertEquals("Check propagated1 equality", prop1, "propagated");
+ assertEquals("Check propagated2 equality", prop2, new Integer(1));
+
+ osgiHelper.getContext().ungetService(msRef);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestMethodProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestMethodProperties.java
new file mode 100644
index 0000000..c707cf4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestMethodProperties.java
@@ -0,0 +1,1647 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+
+public class TestMethodProperties extends Common {
+
+ ComponentInstance instance;
+
+ ComponentInstance instance2;
+
+ ComponentInstance instance3;
+
+
+
+ @Before
+ public void setUp() {
+ Factory fact = ipojoHelper.getFactory("CONFIG-MethodConfigurableCheckService");
+ Properties props = new Properties();
+ props.put("instance.name", "under-test");
+ props.put("b", "1");
+ props.put("s", "1");
+ props.put("i", "1");
+ props.put("l", "1");
+ props.put("d", "1");
+ props.put("f", "1");
+ props.put("c", "a");
+ props.put("bool", "true");
+ props.put("bs", "{1,2,3}");
+ props.put("ss", "{1,2,3}");
+ props.put("is", "{1,2,3}");
+ props.put("ls", "{1,2,3}");
+ props.put("ds", "{1,2,3}");
+ props.put("fs", "{1,2,3}");
+ props.put("cs", "{a,b,c}");
+ props.put("bools", "{true,true,true}");
+ props.put("string", "foo");
+ props.put("strings", "{foo, bar, baz}");
+
+ try {
+ instance = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the under-test instance : " + e.getMessage());
+ }
+
+ Properties props2 = new Properties();
+ props2.put("instance.name", "under-test-2");
+ props2.put("b", new Byte("1"));
+ props2.put("s", new Short("1"));
+ props2.put("i", new Integer("1"));
+ props2.put("l", new Long("1"));
+ props2.put("d", new Double("1"));
+ props2.put("f", new Float("1"));
+ props2.put("c", new Character('a'));
+ props2.put("bool", new Boolean(true));
+ props2.put("bs", new byte[]{1, 2, 3});
+ props2.put("ss", new short[]{1, 2, 3});
+ props2.put("is", new int[]{1, 2, 3});
+ props2.put("ls", new long[]{1, 2, 3});
+ props2.put("ds", new double[]{1, 2, 3});
+ props2.put("fs", new float[]{1, 2, 3});
+ props2.put("cs", new char[]{'a', 'b', 'c'});
+ props2.put("bools", new boolean[]{true, true, true});
+ props2.put("string", "foo");
+ props2.put("strings", new String[]{"foo", "bar", "baz"});
+
+ try {
+ instance2 = fact.createComponentInstance(props2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot create the under-test instance 2 : " + e.getMessage());
+ }
+
+ try {
+ instance3 = fact.createComponentInstance(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot create the under-test instance 3 : " + e.getMessage());
+ }
+
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance = null;
+ instance2 = null;
+ instance3 = null;
+ }
+
+ @Test
+ public void testConfigurationPrimitive() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+//
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationObj() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigure(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ @Test
+ public void testConfigurationObjString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigureString(instance);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ @Test
+ public void testConfigurationPrimitive2() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitive2String() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays2() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays2String() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationObj2() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigure(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ @Test
+ public void testConfigurationObj2String() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigureString(instance2);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ private void reconfigure(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", new Byte("2"));
+ props2.put("s", new Short("2"));
+ props2.put("i", new Integer("2"));
+ props2.put("l", new Long("2"));
+ props2.put("d", new Double("2"));
+ props2.put("f", new Float("2"));
+ props2.put("c", new Character('b'));
+ props2.put("bool", new Boolean(false));
+ props2.put("bs", new byte[]{(byte) 3, (byte) 2, (byte) 1});
+ props2.put("ss", new short[]{(short) 3, (short) 2, (short) 1});
+ props2.put("is", new int[]{3, 2, 1});
+ props2.put("ls", new long[]{3, 2, 1});
+ props2.put("ds", new double[]{3, 2, 1});
+ props2.put("fs", new float[]{3, 2, 1});
+ props2.put("cs", new char[]{'c', 'b', 'a'});
+ props2.put("bools", new boolean[]{false, false, false});
+ props2.put("string", "bar");
+ props2.put("strings", new String[]{"baz", "bar", "foo"});
+
+ ci.reconfigure(props2);
+ }
+
+ private void reconfigureString(ComponentInstance ci) {
+ Properties props2 = new Properties();
+ props2.put("b", "2");
+ props2.put("s", "2");
+ props2.put("i", "2");
+ props2.put("l", "2");
+ props2.put("d", "2");
+ props2.put("f", "2");
+ props2.put("c", "b");
+ props2.put("bool", "false");
+ props2.put("bs", "{3, 2,1}");
+ props2.put("ss", "{3, 2,1}");
+ props2.put("is", "{3, 2,1}");
+ props2.put("ls", "{3, 2,1}");
+ props2.put("ds", "{3, 2,1}");
+ props2.put("fs", "{3, 2,1}");
+ props2.put("cs", "{c, b , a}");
+ props2.put("bools", "{false,false,false}");
+ props2.put("string", "bar");
+ props2.put("strings", "{baz, bar, foo}");
+
+ ci.reconfigure(props2);
+ }
+
+ @Test
+ public void testConfigurationPrimitiveNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("0"));
+ assertEquals("Check s", s, new Short("0"));
+ assertEquals("Check i", i, new Integer("0"));
+ assertEquals("Check l", l, new Long("0"));
+ assertEquals("Check d", d, new Double("0"));
+ assertEquals("Check f", f, new Float("0"));
+ assertEquals("Check c", c, new Character((char) 0));
+ assertEquals("Check bool", bool, new Boolean("false"));
+
+ Integer upb = (Integer) props.get("upb");
+ Integer ups = (Integer) props.get("ups");
+ Integer upi = (Integer) props.get("upi");
+ Integer upl = (Integer) props.get("upl");
+ Integer upd = (Integer) props.get("upd");
+ Integer upf = (Integer) props.get("upf");
+ Integer upc = (Integer) props.get("upc");
+ Integer upbool = (Integer) props.get("upbool");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+ reconfigure(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ upb = (Integer) props.get("upb");
+ ups = (Integer) props.get("ups");
+ upi = (Integer) props.get("upi");
+ upl = (Integer) props.get("upl");
+ upd = (Integer) props.get("upd");
+ upf = (Integer) props.get("upf");
+ upc = (Integer) props.get("upc");
+ upbool = (Integer) props.get("upbool");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ assertEquals("2) Check upbool", upbool, new Integer(1));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("0"));
+ assertEquals("Check s", s, new Short("0"));
+ assertEquals("Check i", i, new Integer("0"));
+ assertEquals("Check l", l, new Long("0"));
+ assertEquals("Check d", d, new Double("0"));
+ assertEquals("Check f", f, new Float("0"));
+ assertEquals("Check c", c, new Character((char) 0));
+ assertEquals("Check bool", bool, new Boolean("false"));
+
+ Integer upb = (Integer) props.get("upb");
+ Integer ups = (Integer) props.get("ups");
+ Integer upi = (Integer) props.get("upi");
+ Integer upl = (Integer) props.get("upl");
+ Integer upd = (Integer) props.get("upd");
+ Integer upf = (Integer) props.get("upf");
+ Integer upc = (Integer) props.get("upc");
+ Integer upbool = (Integer) props.get("upbool");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+ reconfigureString(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+ upb = (Integer) props.get("upb");
+ ups = (Integer) props.get("ups");
+ upi = (Integer) props.get("upi");
+ upl = (Integer) props.get("upl");
+ upd = (Integer) props.get("upd");
+ upf = (Integer) props.get("upf");
+ upc = (Integer) props.get("upc");
+ upbool = (Integer) props.get("upbool");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ assertEquals("2) Check upbool", upbool, new Integer(1));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertNull("Check b nullity", b);
+ assertNull("Check s nullity", s);
+ assertNull("Check i nullity", i);
+ assertNull("Check l nullity", l);
+ assertNull("Check d nullity", d);
+ assertNull("Check f nullity", f);
+ assertNull("Check c nullity", c);
+ assertNull("Check bool nullity", bool);
+
+ Integer upb = (Integer) props.get("upbs");
+ Integer ups = (Integer) props.get("upss");
+ Integer upi = (Integer) props.get("upis");
+ Integer upl = (Integer) props.get("upls");
+ Integer upd = (Integer) props.get("upds");
+ Integer upf = (Integer) props.get("upfs");
+ Integer upc = (Integer) props.get("upcs");
+ Integer upbool = (Integer) props.get("upbools");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+ reconfigure(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ upb = (Integer) props.get("upbs");
+ ups = (Integer) props.get("upss");
+ upi = (Integer) props.get("upis");
+ upl = (Integer) props.get("upls");
+ upd = (Integer) props.get("upds");
+ upf = (Integer) props.get("upfs");
+ upc = (Integer) props.get("upcs");
+ upbool = (Integer) props.get("upbools");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ assertEquals("2) Check upbool", upbool, new Integer(1));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertNull("Check b nullity", b);
+ assertNull("Check s nullity", s);
+ assertNull("Check i nullity", i);
+ assertNull("Check l nullity", l);
+ assertNull("Check d nullity", d);
+ assertNull("Check f nullity", f);
+ assertNull("Check c nullity", c);
+ assertNull("Check bool nullity", bool);
+
+ Integer upb = (Integer) props.get("upbs");
+ Integer ups = (Integer) props.get("upss");
+ Integer upi = (Integer) props.get("upis");
+ Integer upl = (Integer) props.get("upls");
+ Integer upd = (Integer) props.get("upds");
+ Integer upf = (Integer) props.get("upfs");
+ Integer upc = (Integer) props.get("upcs");
+ Integer upbool = (Integer) props.get("upbools");
+
+ assertEquals("Check upb", upb, new Integer(0));
+ assertEquals("Check ups", ups, new Integer(0));
+ assertEquals("Check upi", upi, new Integer(0));
+ assertEquals("Check upl", upl, new Integer(0));
+ assertEquals("Check upd", upd, new Integer(0));
+ assertEquals("Check upf", upf, new Integer(0));
+ assertEquals("Check upc", upc, new Integer(0));
+ assertEquals("Check upbool", upbool, new Integer(0));
+
+
+ reconfigureString(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+ upb = (Integer) props.get("upbs");
+ ups = (Integer) props.get("upss");
+ upi = (Integer) props.get("upis");
+ upl = (Integer) props.get("upls");
+ upd = (Integer) props.get("upds");
+ upf = (Integer) props.get("upfs");
+ upc = (Integer) props.get("upcs");
+ upbool = (Integer) props.get("upbools");
+
+ assertEquals("2) Check upb", upb, new Integer(1));
+ assertEquals("2) Check ups", ups, new Integer(1));
+ assertEquals("2) Check upi", upi, new Integer(1));
+ assertEquals("2) Check upl", upl, new Integer(1));
+ assertEquals("2) Check upd", upd, new Integer(1));
+ assertEquals("2) Check upf", upf, new Integer(1));
+ assertEquals("2) Check upc", upc, new Integer(1));
+ assertEquals("2) Check upbool", upbool, new Integer(1));
+
+ }
+
+ @Test
+ public void testConfigurationObjNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, null);
+ assertEquals("Check strings", ss, null);
+
+
+ Integer upString = (Integer) props.get("upstring");
+ Integer upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("Check upString", upString, new Integer(0));
+ assertEquals("Check upStrings", upStrings, new Integer(0));
+
+ reconfigure(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+ upString = (Integer) props.get("upstring");
+ upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("2) Check upString", upString, new Integer(1));
+ assertEquals("2) Check upStrings", upStrings, new Integer(1));
+ }
+
+ @Test
+ public void testConfigurationObjStringNoValue() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, null);
+ assertEquals("Check strings", ss, null);
+
+
+ Integer upString = (Integer) props.get("upstring");
+ Integer upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("Check upString", upString, new Integer(0));
+ assertEquals("Check upStrings", upStrings, new Integer(0));
+
+ reconfigureString(instance3);
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+ upString = (Integer) props.get("upstring");
+ upStrings = (Integer) props.get("upstrings");
+
+ assertEquals("2) Check upString", upString, new Integer(1));
+ assertEquals("2) Check upStrings", upStrings, new Integer(1));
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertyModifier.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertyModifier.java
new file mode 100644
index 0000000..c1c56f4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertyModifier.java
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import javax.inject.Inject;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.options;
+
+
+public class TestPropertyModifier extends Common {
+
+ @Test
+ public void testPropertyModifier() {
+
+ ComponentInstance ci = null;
+ Factory factory = ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.components.PropertyModifier");
+ Properties props = new Properties();
+ props.put("cls", new String[]{FooService.class.getName()});
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci.getInstanceName());
+ assertNotNull("Check ref", ref);
+
+ // Check the service property
+ // Not exposed here:
+ assertNull("Classes -0", ref.getProperty("classes"));
+
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue(check.check());
+
+ // Property exposed now.
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci.getInstanceName());
+ Class[] str = (Class[]) ref.getProperty("classes");
+ assertEquals("Classes size", 1, str.length);
+ assertEquals("Classes[0]", FooService.class.getName(), str[0].getName());
+
+ Properties p = check.getProps();
+ Class[] str2 = (Class[]) p.get("classes");
+ assertEquals("Classes size -2", 1, str2.length);
+ assertEquals("Classes[0] -2", FooService.class.getName(), str2[0].getName());
+
+ Properties props2 = new Properties();
+ props2.put("cls", new String[]{FooService.class.getName(), CheckService.class.getName()});
+ try {
+ ci.reconfigure(props2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Check the service property
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), ci.getInstanceName());
+ assertNotNull("Check ref", ref);
+ str = (Class[]) ref.getProperty("classes");
+ assertEquals("Classes size -3", 2, str.length);
+ assertEquals("Classes[0] -3", FooService.class.getName(), str[0].getName());
+ assertEquals("Classes[1] -3", CheckService.class.getName(), str[1].getName());
+
+
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ p = check.getProps();
+ str2 = (Class[]) p.get("classes");
+ assertEquals("Classes size -4", 2, str2.length);
+ assertEquals("Classes[0] -4", FooService.class.getName(), str2[0].getName());
+ assertEquals("Classes[1] -4", CheckService.class.getName(), str2[1].getName());
+
+ ci.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleProperties.java
new file mode 100644
index 0000000..0982b00
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimpleProperties.java
@@ -0,0 +1,261 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+
+public class TestSimpleProperties extends Common {
+
+
+ ComponentInstance fooProvider1;
+ ComponentInstance fooProvider2;
+ ComponentInstance fooProvider3;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-Conf";
+
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "FooProvider-1");
+ fooProvider1 = ipojoHelper.createComponentInstance(type, p1);
+
+ Properties p2 = new Properties();
+ p2.put("instance.name", "FooProvider-2");
+ p2.put("int", new Integer(4));
+ p2.put("boolean", new Boolean(false));
+ p2.put("string", new String("bar"));
+ p2.put("strAProp", new String[]{"bar", "foo"});
+ p2.put("intAProp", new int[]{1, 2, 3});
+ fooProvider2 = ipojoHelper.createComponentInstance(type, p2);
+
+ Hashtable<String, String> p3 = new Hashtable<String, String>();
+ p3.put("instance.name", "FooProvider-3");
+ fooProvider3 = ipojoHelper.createComponentInstance("CONFIG-FooProviderType-ConfNoValue", p3);
+ }
+
+ @After
+ public void tearDown() {
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ fooProvider3.dispose();
+ fooProvider1 = null;
+ fooProvider2 = null;
+ fooProvider3 = null;
+ }
+
+ @Test
+ public void testComponentTypeConfiguration() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check FooService availability", ref);
+ FooService fs = (FooService) osgiHelper.getContext().getService(ref);
+ Properties toCheck = fs.fooProps();
+
+ Integer intProp = (Integer) toCheck.get("intProp");
+ Boolean boolProp = (Boolean) toCheck.get("boolProp");
+ String strProp = (String) toCheck.get("strProp");
+ String[] strAProp = (String[]) toCheck.get("strAProp");
+ int[] intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality (1)", intProp, new Integer(2));
+ assertEquals("Check longProp equality (1)", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality (1)", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity (1)", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (1) : " + strAProp[i] + " != " + v[i]);
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (1) : " + intAProp[i] + " != " + v2[i]);
+ }
+ }
+
+ // change the field value
+ assertTrue("Invoke the fs service", fs.foo());
+ toCheck = fs.fooProps();
+
+
+ // Re-check the property (change)
+ intProp = (Integer) toCheck.get("intProp");
+ boolProp = (Boolean) toCheck.get("boolProp");
+ strProp = (String) toCheck.get("strProp");
+ strAProp = (String[]) toCheck.get("strAProp");
+ intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality (2) (" + intProp + ")", intProp, new Integer(3));
+ assertEquals("Check longProp equality (2)", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality (2)", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity (2)", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (2)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity (2)", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (2) : " + intAProp[i] + " != " + v2[i]);
+ }
+ }
+
+ fs = null;
+ osgiHelper.getContext().ungetService(ref);
+ }
+
+
+ @Test
+ public void testInstanceConfiguration() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-2");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ FooService fs = (FooService) osgiHelper.getContext().getService(sr);
+ Properties toCheck = fs.fooProps();
+
+ // Check service properties
+ Integer intProp = (Integer) toCheck.get("intProp");
+ Boolean boolProp = (Boolean) toCheck.get("boolProp");
+ String strProp = (String) toCheck.get("strProp");
+ String[] strAProp = (String[]) toCheck.get("strAProp");
+ int[] intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"bar", "foo"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+
+ assertTrue("invoke fs", fs.foo());
+ toCheck = fs.fooProps();
+
+ // Re-check the property (change)
+ intProp = (Integer) toCheck.get("intProp");
+ boolProp = (Boolean) toCheck.get("boolProp");
+ strProp = (String) toCheck.get("strProp");
+ strAProp = (String[]) toCheck.get("strAProp");
+ intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(3));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ fs = null;
+ osgiHelper.getContext().ungetService(sr);
+ }
+
+ @Test
+ public void testNoValue() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ FooService fs = (FooService) osgiHelper.getContext().getService(sr);
+ Properties toCheck = fs.fooProps();
+
+ // Check service properties
+ Integer intProp = (Integer) toCheck.get("intProp");
+ Boolean boolProp = (Boolean) toCheck.get("boolProp");
+ String strProp = (String) toCheck.get("strProp");
+ String[] strAProp = (String[]) toCheck.get("strAProp");
+ int[] intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality", strProp, null);
+ assertNull("Check strAProp nullity", strAProp);
+ assertNull("Check intAProp nullity", intAProp);
+
+ assertTrue("invoke fs", fs.foo());
+ toCheck = fs.fooProps();
+
+ // Re-check the property (change)
+ intProp = (Integer) toCheck.get("intProp");
+ boolProp = (Boolean) toCheck.get("boolProp");
+ strProp = (String) toCheck.get("strProp");
+ strAProp = (String[]) toCheck.get("strAProp");
+ intAProp = (int[]) toCheck.get("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(3));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ fs = null;
+ osgiHelper.getContext().ungetService(sr);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSuperMethodProperties.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSuperMethodProperties.java
new file mode 100644
index 0000000..c1d4a02
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSuperMethodProperties.java
@@ -0,0 +1,631 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+public class TestSuperMethodProperties extends Common {
+
+ ComponentInstance instance;
+
+ @Before
+ public void setUp() {
+ Factory fact = ipojoHelper.getFactory("CONFIG-ParentMethodConfigurableCheckService");
+ Properties props = new Properties();
+ props.put("instance.name", "under-test");
+ props.put("b", "1");
+ props.put("s", "1");
+ props.put("i", "1");
+ props.put("l", "1");
+ props.put("d", "1");
+ props.put("f", "1");
+ props.put("c", "a");
+ props.put("bool", "true");
+ props.put("bs", "{1,2,3}");
+ props.put("ss", "{1,2,3}");
+ props.put("is", "{1,2,3}");
+ props.put("ls", "{1,2,3}");
+ props.put("ds", "{1,2,3}");
+ props.put("fs", "{1,2,3}");
+ props.put("cs", "{a,b,c}");
+ props.put("bools", "{true,true,true}");
+ props.put("string", "foo");
+ props.put("strings", "{foo, bar, baz}");
+
+ try {
+ instance = fact.createComponentInstance(props);
+ } catch (Exception e) {
+ fail("Cannot create the under-test instance : " + e.getMessage());
+ }
+
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance = null;
+ }
+
+ @Test
+ public void testConfigurationPrimitive() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ Byte b = (Byte) props.get("b");
+ Short s = (Short) props.get("s");
+ Integer i = (Integer) props.get("i");
+ Long l = (Long) props.get("l");
+ Double d = (Double) props.get("d");
+ Float f = (Float) props.get("f");
+ Character c = (Character) props.get("c");
+ Boolean bool = (Boolean) props.get("bool");
+
+ assertEquals("Check b", b, new Byte("1"));
+ assertEquals("Check s", s, new Short("1"));
+ assertEquals("Check i", i, new Integer("1"));
+ assertEquals("Check l", l, new Long("1"));
+ assertEquals("Check d", d, new Double("1"));
+ assertEquals("Check f", f, new Float("1"));
+ assertEquals("Check c", c, new Character('a'));
+ assertEquals("Check bool", bool, new Boolean("true"));
+
+// Integer upb = (Integer) props.get("upb");
+// Integer ups = (Integer) props.get("ups");
+// Integer upi = (Integer) props.get("upi");
+// Integer upl = (Integer) props.get("upl");
+// Integer upd = (Integer) props.get("upd");
+// Integer upf = (Integer) props.get("upf");
+// Integer upc = (Integer) props.get("upc");
+// Integer upbool = (Integer) props.get("upbool");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (Byte) props.get("b");
+ s = (Short) props.get("s");
+ i = (Integer) props.get("i");
+ l = (Long) props.get("l");
+ d = (Double) props.get("d");
+ f = (Float) props.get("f");
+ c = (Character) props.get("c");
+ bool = (Boolean) props.get("bool");
+
+ assertEquals("2) Check b (" + b + ")", b, new Byte("2"));
+ assertEquals("2) Check s", s, new Short("2"));
+ assertEquals("2) Check i", i, new Integer("2"));
+ assertEquals("2) Check l", l, new Long("2"));
+ assertEquals("2) Check d", d, new Double("2"));
+ assertEquals("2) Check f", f, new Float("2"));
+ assertEquals("2) Check c", c, new Character('b'));
+ assertEquals("2) Check bool", bool, new Boolean("false"));
+
+// upb = (Integer) props.get("upb");
+// ups = (Integer) props.get("ups");
+// upi = (Integer) props.get("upi");
+// upl = (Integer) props.get("upl");
+// upd = (Integer) props.get("upd");
+// upf = (Integer) props.get("upf");
+// upc = (Integer) props.get("upc");
+// upbool = (Integer) props.get("upbool");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArrays() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigure();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationPrimitiveArraysString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ byte[] b = (byte[]) props.get("bs");
+ short[] s = (short[]) props.get("ss");
+ int[] i = (int[]) props.get("is");
+ long[] l = (long[]) props.get("ls");
+ double[] d = (double[]) props.get("ds");
+ float[] f = (float[]) props.get("fs");
+ char[] c = (char[]) props.get("cs");
+ boolean[] bool = (boolean[]) props.get("bools");
+
+ assertEquals("Check b 0", b[0], 1);
+ assertEquals("Check b 1", b[1], 2);
+ assertEquals("Check b 2", b[2], 3);
+ assertEquals("Check s 0", s[0], 1);
+ assertEquals("Check s 1", s[1], 2);
+ assertEquals("Check s 2", s[2], 3);
+ assertEquals("Check i 0", i[0], 1);
+ assertEquals("Check i 1", i[1], 2);
+ assertEquals("Check i 2", i[2], 3);
+ assertEquals("Check l 0", l[0], 1);
+ assertEquals("Check l 1", l[1], 2);
+ assertEquals("Check l 2", l[2], 3);
+ assertEquals("Check d 0", d[0], 1, 0);
+ assertEquals("Check d 1", d[1], 2, 0);
+ assertEquals("Check d 2", d[2], 3, 0);
+ assertEquals("Check f 0", f[0], 1, 0);
+ assertEquals("Check f 1", f[1], 2, 0);
+ assertEquals("Check f 2", f[2], 3, 0);
+ assertEquals("Check c 0", c[0], 'a');
+ assertEquals("Check c 1", c[1], 'b');
+ assertEquals("Check c 2", c[2], 'c');
+ assertTrue("Check bool 0", bool[0]);
+ assertTrue("Check bool 1", bool[0]);
+ assertTrue("Check bool 2", bool[0]);
+
+// Integer upb = (Integer) props.get("upbs");
+// Integer ups = (Integer) props.get("upss");
+// Integer upi = (Integer) props.get("upis");
+// Integer upl = (Integer) props.get("upls");
+// Integer upd = (Integer) props.get("upds");
+// Integer upf = (Integer) props.get("upfs");
+// Integer upc = (Integer) props.get("upcs");
+// Integer upbool = (Integer) props.get("upbools");
+//
+// assertEquals("Check upb", upb, new Integer(1));
+// assertEquals("Check ups", ups, new Integer(1));
+// assertEquals("Check upi", upi, new Integer(1));
+// assertEquals("Check upl", upl, new Integer(1));
+// assertEquals("Check upd", upd, new Integer(1));
+// assertEquals("Check upf", upf, new Integer(1));
+// assertEquals("Check upc", upc, new Integer(1));
+// assertEquals("Check upbool", upbool, new Integer(1));
+
+ reconfigureString();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ b = (byte[]) props.get("bs");
+ s = (short[]) props.get("ss");
+ i = (int[]) props.get("is");
+ l = (long[]) props.get("ls");
+ d = (double[]) props.get("ds");
+ f = (float[]) props.get("fs");
+ c = (char[]) props.get("cs");
+ bool = (boolean[]) props.get("bools");
+
+ assertEquals("2) Check b 0", b[0], 3);
+ assertEquals("2) Check b 1", b[1], 2);
+ assertEquals("2) Check b 2", b[2], 1);
+ assertEquals("2) Check s 0", s[0], 3);
+ assertEquals("2) Check s 1", s[1], 2);
+ assertEquals("2) Check s 2", s[2], 1);
+ assertEquals("2) Check i 0", i[0], 3);
+ assertEquals("2) Check i 1", i[1], 2);
+ assertEquals("2) Check i 2", i[2], 1);
+ assertEquals("2) Check l 0", l[0], 3);
+ assertEquals("2) Check l 1", l[1], 2);
+ assertEquals("2) Check l 2", l[2], 1);
+ assertEquals("2) Check d 0", d[0], 3, 0);
+ assertEquals("2) Check d 1", d[1], 2, 0);
+ assertEquals("2) Check d 2", d[2], 1, 0);
+ assertEquals("2) Check f 0", f[0], 3, 0);
+ assertEquals("2) Check f 1", f[1], 2, 0);
+ assertEquals("2) Check f 2", f[2], 1, 0);
+ assertEquals("2) Check c 0", c[0], 'c');
+ assertEquals("2) Check c 1", c[1], 'b');
+ assertEquals("2) Check c 2", c[2], 'a');
+ assertFalse("2) Check bool 0", bool[0]);
+ assertFalse("2) Check bool 1", bool[0]);
+ assertFalse("2) Check bool 2", bool[0]);
+
+// upb = (Integer) props.get("upbs");
+// ups = (Integer) props.get("upss");
+// upi = (Integer) props.get("upis");
+// upl = (Integer) props.get("upls");
+// upd = (Integer) props.get("upds");
+// upf = (Integer) props.get("upfs");
+// upc = (Integer) props.get("upcs");
+// upbool = (Integer) props.get("upbools");
+//
+// assertEquals("2) Check upb", upb, new Integer(2));
+// assertEquals("2) Check ups", ups, new Integer(2));
+// assertEquals("2) Check upi", upi, new Integer(2));
+// assertEquals("2) Check upl", upl, new Integer(2));
+// assertEquals("2) Check upd", upd, new Integer(2));
+// assertEquals("2) Check upf", upf, new Integer(2));
+// assertEquals("2) Check upc", upc, new Integer(2));
+// assertEquals("2) Check upbool", upbool, new Integer(2));
+
+ }
+
+ @Test
+ public void testConfigurationObj() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigure();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ @Test
+ public void testConfigurationObjString() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties props = check.getProps();
+
+ String s = (String) props.get("string");
+ String[] ss = (String[]) props.get("strings");
+
+ assertEquals("Check string", s, "foo");
+ assertEquals("Check strings 0", ss[0], "foo");
+ assertEquals("Check strings 1", ss[1], "bar");
+ assertEquals("Check strings 2", ss[2], "baz");
+
+// Integer upString = (Integer) props.get("upstring");
+// Integer upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("Check upString", upString, new Integer(1));
+// assertEquals("Check upStrings", upStrings, new Integer(1));
+
+ reconfigureString();
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Test check service availability", ref);
+ check = (CheckService) osgiHelper.getRawServiceObject(ref);
+ props = check.getProps();
+
+ s = (String) props.get("string");
+ ss = (String[]) props.get("strings");
+
+ assertEquals("2) Check string", s, "bar");
+ assertEquals("2) Check strings 0", ss[0], "baz");
+ assertEquals("2) Check strings 1", ss[1], "bar");
+ assertEquals("2) Check strings 2", ss[2], "foo");
+
+// upString = (Integer) props.get("upstring");
+// upStrings = (Integer) props.get("upstrings");
+//
+// assertEquals("2) Check upString", upString, new Integer(2));
+// assertEquals("2) Check upStrings", upStrings, new Integer(2));
+ }
+
+ private void reconfigure() {
+ Properties props2 = new Properties();
+ props2.put("instance.name", "under-test");
+ props2.put("b", new Byte("2"));
+ props2.put("s", new Short("2"));
+ props2.put("i", new Integer("2"));
+ props2.put("l", new Long("2"));
+ props2.put("d", new Double("2"));
+ props2.put("f", new Float("2"));
+ props2.put("c", new Character('b'));
+ props2.put("bool", new Boolean(false));
+ props2.put("bs", new byte[]{(byte) 3, (byte) 2, (byte) 1});
+ props2.put("ss", new short[]{(short) 3, (short) 2, (short) 1});
+ props2.put("is", new int[]{3, 2, 1});
+ props2.put("ls", new long[]{3, 2, 1});
+ props2.put("ds", new double[]{3, 2, 1});
+ props2.put("fs", new float[]{3, 2, 1});
+ props2.put("cs", new char[]{'c', 'b', 'a'});
+ props2.put("bools", new boolean[]{false, false, false});
+ props2.put("string", "bar");
+ props2.put("strings", new String[]{"baz", "bar", "foo"});
+
+ instance.reconfigure(props2);
+ }
+
+ private void reconfigureString() {
+ Properties props2 = new Properties();
+ props2.put("instance.name", "under-test");
+ props2.put("b", "2");
+ props2.put("s", "2");
+ props2.put("i", "2");
+ props2.put("l", "2");
+ props2.put("d", "2");
+ props2.put("f", "2");
+ props2.put("c", "b");
+ props2.put("bool", "false");
+ props2.put("bs", "{3, 2,1}");
+ props2.put("ss", "{3, 2,1}");
+ props2.put("is", "{3, 2,1}");
+ props2.put("ls", "{3, 2,1}");
+ props2.put("ds", "{3, 2,1}");
+ props2.put("fs", "{3, 2,1}");
+ props2.put("cs", "{c, b , a}");
+ props2.put("bools", "{false,false,false}");
+ props2.put("string", "bar");
+ props2.put("strings", "{baz, bar, foo}");
+
+ instance.reconfigure(props2);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethod.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethod.java
new file mode 100644
index 0000000..5852f7e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethod.java
@@ -0,0 +1,218 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+public class TestUpdatedMethod extends Common {
+
+ ComponentInstance fooProvider1;
+ ComponentInstance fooProvider2;
+ ComponentInstance fooProvider3;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-ConfUpdated";
+
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "FooProvider-1");
+ fooProvider1 = ipojoHelper.createComponentInstance(type, p1);
+
+ Properties p2 = new Properties();
+ p2.put("instance.name", "FooProvider-2");
+ p2.put("int", 4);
+ p2.put("boolean", false);
+ p2.put("string", "bar");
+ p2.put("strAProp", new String[]{"bar", "foo"});
+ p2.put("intAProp", new int[]{1, 2, 3});
+ fooProvider2 = ipojoHelper.createComponentInstance(type, p2);
+
+ Hashtable<String, String> p3 = new Hashtable<String, String>();
+ p3.put("instance.name", "FooProvider-3");
+ fooProvider3 = ipojoHelper.createComponentInstance("CONFIG-FooProviderType-ConfNoValueUpdated", p3);
+ }
+
+ @After
+ public void tearDown() {
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ fooProvider3.dispose();
+ fooProvider1 = null;
+ fooProvider2 = null;
+ fooProvider3 = null;
+ }
+
+ @Test
+ public void testComponentTypeConfiguration() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check FooService availability", ref);
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ Properties toCheck = fs.fooProps();
+
+ Integer intProp = (Integer) toCheck.get("intProp");
+ Boolean boolProp = (Boolean) toCheck.get("boolProp");
+ String strProp = (String) toCheck.get("strProp");
+ String[] strAProp = (String[]) toCheck.get("strAProp");
+ int[] intAProp = (int[]) toCheck.get("intAProp");
+
+ // Check updated
+ Integer updated = (Integer) toCheck.get("updated");
+ Dictionary dict = (Dictionary) toCheck.get("lastupdated");
+
+ assertEquals("Check intProp equality (1)", intProp, new Integer(2));
+ assertEquals("Check longProp equality (1)", boolProp, false);
+ assertEquals("Check strProp equality (1)", strProp, "foo");
+ assertNotNull("Check strAProp not nullity (1)", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (1) : " + strAProp[i] + " != " + v[i]);
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (1) : " + intAProp[i] + " != " + v2[i]);
+ }
+ }
+
+ assertEquals("updated count ", 1, updated.intValue());
+ assertEquals("Last updated", 5, dict.size());
+
+ // change the field value
+ assertTrue("Invoke the fs service", fs.foo());
+ toCheck = fs.fooProps();
+
+
+ // Re-check the property (change)
+ intProp = (Integer) toCheck.get("intProp");
+ boolProp = (Boolean) toCheck.get("boolProp");
+ strProp = (String) toCheck.get("strProp");
+ strAProp = (String[]) toCheck.get("strAProp");
+ intAProp = (int[]) toCheck.get("intAProp");
+
+ // Check updated
+ updated = (Integer) toCheck.get("updated");
+ dict = (Dictionary) toCheck.get("lastupdated");
+
+ assertEquals("Check intProp equality (2) (" + intProp + ")", intProp, new Integer(3));
+ assertEquals("Check longProp equality (2)", boolProp, true);
+ assertEquals("Check strProp equality (2)", strProp, "bar");
+ assertNotNull("Check strAProp not nullity (2)", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (2)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity (2)", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (2) : " + intAProp[i] + " != " + v2[i]);
+ }
+ }
+
+ // This does not reconfigure...
+ assertEquals("updated count -2 ", 1, updated.intValue());
+ assertEquals("Last update - 2", 5, dict.size());
+
+ fs = null;
+ }
+
+ @Test
+ public void testNoValue() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ Properties toCheck = fs.fooProps();
+
+ // Check service properties
+ Integer intProp = (Integer) toCheck.get("intProp");
+ Boolean boolProp = (Boolean) toCheck.get("boolProp");
+ String strProp = (String) toCheck.get("strProp");
+ String[] strAProp = (String[]) toCheck.get("strAProp");
+ int[] intAProp = (int[]) toCheck.get("intAProp");
+
+ // Check updated
+ Integer updated = (Integer) toCheck.get("updated");
+ Dictionary dict = (Dictionary) toCheck.get("lastupdated");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, false);
+ assertEquals("Check strProp equality", strProp, null);
+ assertNull("Check strAProp nullity", strAProp);
+ assertNull("Check intAProp nullity", intAProp);
+
+ assertEquals("updated count ", 1, updated.intValue());
+ assertEquals("Last update", 0, dict.size());
+
+ assertTrue("invoke fs", fs.foo());
+ toCheck = fs.fooProps();
+
+ // Re-check the property (change)
+ intProp = (Integer) toCheck.get("intProp");
+ boolProp = (Boolean) toCheck.get("boolProp");
+ strProp = (String) toCheck.get("strProp");
+ strAProp = (String[]) toCheck.get("strAProp");
+ intAProp = (int[]) toCheck.get("intAProp");
+
+ updated = (Integer) toCheck.get("updated");
+ dict = (Dictionary) toCheck.get("lastupdated");
+
+ assertEquals("Check intProp equality", intProp, new Integer(3));
+ assertEquals("Check longProp equality", boolProp, true);
+ assertEquals("Check strProp equality", strProp, "bar");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ fs = null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndConfigAdmin.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndConfigAdmin.java
new file mode 100644
index 0000000..c2b1d8e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndConfigAdmin.java
@@ -0,0 +1,330 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+
+@ExamReactorStrategy(PerMethod.class)
+public class TestUpdatedMethodAndConfigAdmin extends Common {
+
+ ComponentInstance instance, instance2;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-3Updated";
+
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ instance = ipojoHelper.createComponentInstance(type, p1);
+
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance2");
+
+ instance2 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance2.dispose();
+ instance2 = null;
+ instance = null;
+ }
+
+ @Test
+ public void testStatic() throws IOException, InterruptedException {
+
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ System.out.println("Dictionary : " + dict);
+ assertEquals("Check last updated", 3, dict.size()); // foo bar and baz as a service prooperties.
+ }
+
+ @Test
+ public void testStaticNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+ }
+
+ @Test
+ public void testDynamic() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+ }
+
+ @Test
+ public void testDynamicNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ }
+
+
+ @Test
+ public void testDynamicString() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", "0");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndManagedService.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndManagedService.java
new file mode 100644
index 0000000..6c96562
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedMethodAndManagedService.java
@@ -0,0 +1,405 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertNotNull;
+
+
+@ExamReactorStrategy(PerMethod.class)
+public class TestUpdatedMethodAndManagedService extends Common {
+
+ /**
+ * Instance where the ManagedServicePID is provided by the component type.
+ */
+ ComponentInstance instance1;
+ /**
+ * Instance where the ManagedServicePID is provided by the instance.
+ */
+ ComponentInstance instance2;
+
+ /**
+ * Instance without configuration.
+ */
+ ComponentInstance instance3;
+
+ @Before
+ public void setUp() throws IOException {
+
+ for (HandlerFactory handler : osgiHelper.getServiceObjects(HandlerFactory.class)) {
+ System.out.println("handler : " + handler.getHandlerName() + " - " + handler.getState() + " - " + handler
+ .getMissingHandlers());
+ }
+
+ String type = "CONFIG-FooProviderType-4Updated";
+ Hashtable<String, String> p = new Hashtable<String, String>();
+ p.put("instance.name", "instance");
+ p.put("foo", "foo");
+ p.put("bar", "2");
+ p.put("baz", "baz");
+ instance1 = ipojoHelper.createComponentInstance(type, p);
+ System.out.println(instance1.getInstanceDescription().getDescription());
+
+ assertEquals("instance1 created", ComponentInstance.VALID, instance1.getState());
+
+ System.out.println(instance1.getInstanceDescription().getDescription());
+
+ type = "CONFIG-FooProviderType-3Updated";
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance-2");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ p1.put("managed.service.pid", "instance-managed-service");
+ instance2 = ipojoHelper.createComponentInstance(type, p1);
+
+ type = "CONFIG-FooProviderType-3Updated";
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance-3");
+ p2.put("managed.service.pid", "instance-3");
+ instance3 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ }
+
+
+ @Test
+ public void testStaticInstance1() throws IOException {
+ for (Architecture architecture : osgiHelper.getServiceObjects(Architecture.class)) {
+ System.out.println(architecture.getInstanceDescription().getName() + " " + architecture
+ .getInstanceDescription().getState());
+ }
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(),
+ "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ }
+
+ @Test
+ public void testStaticInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(),
+ "instance-managed-service");
+ assertNotNull("Check ManagedService availability", msRef);
+
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+ dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+ }
+
+ @Test
+ public void testDynamicInstance1() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(),
+ "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated -1", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+ dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+ }
+
+ @Test
+ public void testDynamicInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(),
+ "instance-managed-service");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ Dictionary dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+ dict = (Dictionary) fs.fooProps().get("lastupdated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+ assertEquals("Check last updated", 3, dict.size());
+
+ }
+
+ public static void dump(BundleContext bc, File output) throws IOException {
+ if (!output.exists()) {
+ output.mkdirs();
+ }
+
+ for (Bundle bundle : bc.getBundles()) {
+ if (bundle.getBundleId() == 0) {
+ continue;
+ }
+ System.out.println("Location : " + bundle.getLocation());
+ if ("local".equals(bundle.getLocation())) {
+ continue; // Pax Exam, when you hug me, I feel so...
+ }
+ URL location = new URL(bundle.getLocation());
+ FileOutputStream outputStream = null;
+ if (bundle.getVersion() != null) {
+ outputStream = new FileOutputStream(new File(output,
+ bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + ".jar"));
+ } else {
+ outputStream = new FileOutputStream(new File(output, bundle.getSymbolicName() + ".jar"));
+ }
+
+ int read = 0;
+ byte[] bytes = new byte[1024];
+
+ InputStream inputStream = location.openStream();
+ while ((read = inputStream.read(bytes)) != -1) {
+ outputStream.write(bytes, 0, read);
+ }
+ inputStream.close();
+ outputStream.close();
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndConfigAdmin.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndConfigAdmin.java
new file mode 100644
index 0000000..a9e1475
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndConfigAdmin.java
@@ -0,0 +1,319 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+
+@ExamReactorStrategy(PerMethod.class)
+public class TestUpdatedNoArgMethodAndConfigAdmin extends Common {
+
+ ComponentInstance instance, instance2;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-3Updated2";
+
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ instance = ipojoHelper.createComponentInstance(type, p1);
+
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance2");
+
+ instance2 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ instance2.dispose();
+ instance2 = null;
+ instance = null;
+ }
+
+ @Test
+ public void testStatic() throws IOException, InterruptedException {
+
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+
+ }
+
+ @Test
+ public void testStaticNoValue() throws InterruptedException, IOException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin ad = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ }
+
+ @Test
+ public void testDynamic() throws InterruptedException, IOException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ }
+
+ @Test
+ public void testDynamicNoValue() throws IOException, InterruptedException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ Object fooP = fooRef.getProperty("foo");
+ Object barP = fooRef.getProperty("bar");
+ Object bazP = fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, null);
+ assertEquals("Check bar equality -1", barP, null);
+ assertEquals("Check baz equality -1", bazP, null);
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance2.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ }
+
+
+ @Test
+ public void testDynamicString() throws InterruptedException, IOException {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ assertNotNull("Check Configuration Admin availability", admin);
+
+ Configuration configuration = admin.getConfiguration(instance.getInstanceName(),
+ getTestBundle().getLocation());
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", "0");
+
+ // Asynchronous dispatching of the configuration
+ configuration.update(conf);
+ grace();
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndManagedService.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndManagedService.java
new file mode 100644
index 0000000..0065c9b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUpdatedNoArgMethodAndManagedService.java
@@ -0,0 +1,325 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertNotNull;
+
+
+public class TestUpdatedNoArgMethodAndManagedService extends Common {
+
+ /**
+ * Instance where the ManagedServicePID is provided by the component type.
+ */
+ ComponentInstance instance1;
+ /**
+ * Instance where the ManagedServicePID is provided by the instance.
+ */
+ ComponentInstance instance2;
+
+ /**
+ * Instance without configuration.
+ */
+ ComponentInstance instance3;
+
+ @Before
+ public void setUp() {
+ String type = "CONFIG-FooProviderType-4Updated2";
+ Hashtable<String, String> p = new Hashtable<String, String>();
+ p.put("instance.name", "any-instance");
+ p.put("foo", "foo");
+ p.put("bar", "2");
+ p.put("baz", "baz");
+ instance1 = ipojoHelper.createComponentInstance(type, p);
+ assertEquals("instance1 created", ComponentInstance.VALID, instance1.getState());
+
+ type = "CONFIG-FooProviderType-3Updated2";
+ Hashtable<String, String> p1 = new Hashtable<String, String>();
+ p1.put("instance.name", "instance-2");
+ p1.put("foo", "foo");
+ p1.put("bar", "2");
+ p1.put("baz", "baz");
+ p1.put("managed.service.pid", "instanceMSP");
+ instance2 = ipojoHelper.createComponentInstance(type, p1);
+
+ type = "CONFIG-FooProviderType-3Updated2";
+ Hashtable<String, String> p2 = new Hashtable<String, String>();
+ p2.put("instance.name", "instance-3");
+ p2.put("managed.service.pid", "instance-3");
+ instance3 = ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ }
+
+ @Test
+ public void testStaticInstance1() {
+ ServiceReference fooRef = osgiHelper.waitForService(FooService.class.getName(),
+ "(instance.name=" + instance1.getInstanceName() + ")",
+ 5000);
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+ assertEquals("Check updated", 1, updated.intValue());
+ }
+
+ @Test
+ public void testStaticInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -1", fooP, "foo");
+ assertEquals("Check bar equality -1", barP, new Integer(2));
+ assertEquals("Check baz equality -1", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instanceMSP");
+ assertNotNull("Check ManagedService availability", msRef);
+
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("bar", new Integer(2));
+ conf.put("foo", "foo");
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+ assertEquals("Check foo equality -2", fooP, "foo");
+ assertEquals("Check bar equality -2", barP, new Integer(2));
+ assertEquals("Check baz equality -2", bazP, "zab");
+
+ // Get Service
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+ }
+
+ @Test
+ public void testDynamicInstance1() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "FooProvider-3");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Re-check props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance1.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated -1", 1, updated.intValue());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+
+ }
+
+ @Test
+ public void testDynamicInstance2() {
+ ServiceReference fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check FS availability", fooRef);
+
+ String fooP = (String) fooRef.getProperty("foo");
+ Integer barP = (Integer) fooRef.getProperty("bar");
+ String bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "foo");
+ assertEquals("Check bar equality", barP, new Integer(2));
+ assertEquals("Check baz equality", bazP, "baz");
+
+ ServiceReference msRef = osgiHelper.getServiceReferenceByPID(ManagedService.class.getName(), "instanceMSP");
+ assertNotNull("Check ManagedServiceFactory availability", msRef);
+
+ // Configuration of baz
+ Dictionary<String, Object> conf = new Hashtable<String, Object>();
+ conf.put("baz", "zab");
+ conf.put("foo", "oof");
+ conf.put("bar", new Integer(0));
+ ManagedService ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ // Recheck props
+ fooRef = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), instance2.getInstanceName());
+ fooP = (String) fooRef.getProperty("foo");
+ barP = (Integer) fooRef.getProperty("bar");
+ bazP = (String) fooRef.getProperty("baz");
+
+ assertEquals("Check foo equality", fooP, "oof");
+ assertEquals("Check bar equality", barP, new Integer(0));
+ assertEquals("Check baz equality", bazP, "zab");
+
+ // Check field value
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(fooRef);
+ Properties p = fs.fooProps();
+ fooP = (String) p.get("foo");
+ barP = (Integer) p.get("bar");
+
+ assertEquals("Check foo field equality", fooP, "oof");
+ assertEquals("Check bar field equality", barP, new Integer(0));
+
+ Integer updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated", 1, updated.intValue());
+
+ conf.put("baz", "zab2");
+ conf.put("foo", "oof2");
+ conf.put("bar", new Integer(0));
+ ms = (ManagedService) osgiHelper.getRawServiceObject(msRef);
+ try {
+ ms.updated(conf);
+ } catch (ConfigurationException e) {
+ fail("Configuration Exception : " + e);
+ }
+
+ updated = (Integer) fs.fooProps().get("updated");
+
+ assertEquals("Check updated -2", 2, updated.intValue());
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-context-injection-test/pom.xml
new file mode 100644
index 0000000..4b0f98e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-context-injection-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingConstructor.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingConstructor.java
new file mode 100644
index 0000000..287025a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingConstructor.java
@@ -0,0 +1,52 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using constructor injection to retrieve the bundle context.
+ */
+public class ComponentUsingConstructor implements CheckService {
+
+
+ private BundleContext context;
+
+ public ComponentUsingConstructor(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingField.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingField.java
new file mode 100644
index 0000000..d256ba6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingField.java
@@ -0,0 +1,49 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using field injection to retrieve the bundle context.
+ */
+public class ComponentUsingField implements CheckService {
+
+ // Injected.
+ private BundleContext context;
+
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingMethod.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingMethod.java
new file mode 100644
index 0000000..1be690b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ComponentUsingMethod.java
@@ -0,0 +1,51 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using method injection to retrieve the bundle context.
+ */
+public class ComponentUsingMethod implements CheckService {
+
+ private BundleContext context;
+
+ public void setContext(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInConstructor.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInConstructor.java
new file mode 100644
index 0000000..60af998
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInConstructor.java
@@ -0,0 +1,60 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using constructor injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class ComponentBundleContextInjectionInConstructor implements CheckService {
+
+
+ private BundleContext context;
+
+ /**
+ * @param context no parameter, as component is the default.
+ */
+ public ComponentBundleContextInjectionInConstructor(@Context BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInField.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInField.java
new file mode 100644
index 0000000..0b0f90f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInField.java
@@ -0,0 +1,54 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using field injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class ComponentBundleContextInjectionInField implements CheckService {
+
+ @Context(Context.Source.COMPONENT)
+ private BundleContext context;
+
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInMethod.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInMethod.java
new file mode 100644
index 0000000..b97e020
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentBundleContextInjectionInMethod.java
@@ -0,0 +1,57 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using method injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class ComponentBundleContextInjectionInMethod implements CheckService {
+
+ private BundleContext context;
+
+ @Context
+ public void setContext(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithThreeConstructorParams.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithThreeConstructorParams.java
new file mode 100644
index 0000000..ae69c9c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithThreeConstructorParams.java
@@ -0,0 +1,69 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component receiving both bundle context.
+ */
+@Component
+@Provides
+public class ComponentWithThreeConstructorParams implements CheckService {
+
+ private final BundleContext bc;
+ private BundleContext instance;
+
+ private BundleContext component;
+
+ public ComponentWithThreeConstructorParams(BundleContext bc, @Context(Context.Source.INSTANCE) BundleContext
+ instance,
+ @Context BundleContext component) {
+ this.instance = instance;
+ this.component = component;
+ this.bc = bc;
+ }
+
+ @Override
+ public boolean check() {
+ return instance != null && component != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (instance != null) {
+ map.put("instance", instance);
+ }
+ if (component != null) {
+ map.put("component", component);
+ }
+ if (bc != null) {
+ map.put("bc", bc);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoConstructorParams.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoConstructorParams.java
new file mode 100644
index 0000000..8008e82
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoConstructorParams.java
@@ -0,0 +1,63 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component receiving both bundle context.
+ */
+@Component
+@Provides
+public class ComponentWithTwoConstructorParams implements CheckService {
+
+ private BundleContext instance;
+
+ private BundleContext component;
+
+ public ComponentWithTwoConstructorParams(@Context(Context.Source.INSTANCE) BundleContext instance,
+ @Context BundleContext component) {
+ this.instance = instance;
+ this.component = component;
+ }
+
+ @Override
+ public boolean check() {
+ return instance != null && component != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (instance != null) {
+ map.put("instance", instance);
+ }
+ if (component != null) {
+ map.put("component", component);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoFields.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoFields.java
new file mode 100644
index 0000000..bf32d02
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoFields.java
@@ -0,0 +1,60 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component receiving both bundle context.
+ */
+@Component
+@Provides
+public class ComponentWithTwoFields implements CheckService {
+
+ @Context(Context.Source.INSTANCE)
+ private BundleContext instance;
+
+ @Context(Context.Source.COMPONENT)
+ private BundleContext component;
+
+
+ @Override
+ public boolean check() {
+ return instance != null && component != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (instance != null) {
+ map.put("instance", instance);
+ }
+ if (component != null) {
+ map.put("component", component);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoSetters.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoSetters.java
new file mode 100644
index 0000000..b69e0ec
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/ComponentWithTwoSetters.java
@@ -0,0 +1,66 @@
+/*
+ * 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component receiving both bundle context.
+ */
+@Component
+@Provides
+public class ComponentWithTwoSetters implements CheckService {
+
+ private BundleContext instance;
+ private BundleContext component;
+
+ @Context(Context.Source.INSTANCE)
+ public void setInstanceContext(BundleContext context) {
+ this.instance = context;
+ }
+
+ @Context(Context.Source.COMPONENT)
+ public void setComponentContext(BundleContext context) {
+ this.component = context;
+ }
+
+ @Override
+ public boolean check() {
+ return instance != null && component != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (instance != null) {
+ map.put("instance", instance);
+ }
+ if (component != null) {
+ map.put("component", component);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInConstructor.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInConstructor.java
new file mode 100644
index 0000000..7df6fd9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInConstructor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using constructor injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class InstanceBundleContextInjectionInConstructor implements CheckService {
+
+
+ private BundleContext context;
+
+ public InstanceBundleContextInjectionInConstructor(@Context(Context.Source.INSTANCE) BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInField.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInField.java
new file mode 100644
index 0000000..fa0399e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInField.java
@@ -0,0 +1,54 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using field injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class InstanceBundleContextInjectionInField implements CheckService {
+
+ @Context(Context.Source.INSTANCE)
+ private BundleContext context;
+
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInMethod.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInMethod.java
new file mode 100644
index 0000000..7a83414
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/annotations/InstanceBundleContextInjectionInMethod.java
@@ -0,0 +1,57 @@
+/*
+* 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.annotations;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using method injection to retrieve the bundle context.
+ */
+@Component
+@Provides
+public class InstanceBundleContextInjectionInMethod implements CheckService {
+
+ private BundleContext context;
+
+ @Context(Context.Source.INSTANCE)
+ public void setContext(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, BundleContext> map = new HashMap<String, BundleContext>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java
new file mode 100644
index 0000000..eb0e505
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/configuration/MyConfiguration.java
@@ -0,0 +1,31 @@
+/*
+* 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.configuration;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.apache.felix.ipojo.configuration.Instance;
+import org.apache.felix.ipojo.runtime.core.components.annotations.InstanceBundleContextInjectionInField;
+
+import static org.apache.felix.ipojo.configuration.Instance.instance;
+
+@Configuration
+public class MyConfiguration {
+
+ Instance instance1 = instance().of(InstanceBundleContextInjectionInField.class).named("from.configuration");
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties1.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties1.java
new file mode 100644
index 0000000..43fd99f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties1.java
@@ -0,0 +1,64 @@
+/*
+* 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.mix;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using constructor injection to retrieve the bundle context and a property.
+ * In this component the property is first.
+ */
+@Component
+@Provides
+public class MixWithProperties1 implements CheckService {
+
+
+ private final String message;
+ private final BundleContext context;
+
+ public MixWithProperties1(@Property(name = "message") String message, @Context BundleContext context) {
+ this.context = context;
+ this.message = message;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, Object> map = new HashMap<String, Object>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ if (message != null) {
+ map.put("message", message);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties2.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties2.java
new file mode 100644
index 0000000..2a8455f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/mix/MixWithProperties2.java
@@ -0,0 +1,64 @@
+/*
+* 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.mix;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Context;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A component using constructor injection to retrieve the bundle context and a property.
+ * In this component the property is last.
+ */
+@Component
+@Provides
+public class MixWithProperties2 implements CheckService {
+
+
+ private final String message;
+ private final BundleContext context;
+
+ public MixWithProperties2(@Context BundleContext context, @Property(name = "message") String message) {
+ this.context = context;
+ this.message = message;
+ }
+
+ @Override
+ public boolean check() {
+ return context != null;
+ }
+
+ @Override
+ public Map map() {
+ Map<String, Object> map = new HashMap<String, Object>();
+ if (context != null) {
+ map.put("context", context);
+ }
+ if (message != null) {
+ map.put("message", message);
+ }
+ return map;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..c3f2096
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Map;
+
+public interface CheckService {
+
+ public boolean check();
+
+ public Map map();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..10b64cc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/main/resources/metadata.xml
@@ -0,0 +1,65 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingField"
+ name="CTX-Field-Component" architecture="true">
+ <provides/>
+ <!-- component is default -->
+ <context field="context"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingField"
+ name="CTX-Field-Instance" architecture="true">
+ <provides/>
+ <context field="context" context="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingMethod"
+ name="CTX-Method-Component" architecture="true">
+ <provides/>
+ <!-- component is default -->
+ <context method="setContext"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingMethod"
+ name="CTX-Method-Instance" architecture="true">
+ <provides/>
+ <!-- component is default -->
+ <context method="setContext" context="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingConstructor"
+ name="CTX-Constructor-Component" architecture="true">
+ <provides/>
+ <context constructor-parameter="0" context="component"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ComponentUsingConstructor"
+ name="CTX-Constructor-Instance" architecture="true">
+ <provides/>
+ <context constructor-parameter="0" context="instance"/>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..0ba6a79
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ // No custom configuration required.
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromAnnotations.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromAnnotations.java
new file mode 100644
index 0000000..37461a8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromAnnotations.java
@@ -0,0 +1,129 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNotSame;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Checks that contexts are correctly injected.
+ * For instance bundle context, we use the 'instance.bundle.context' hidden configuration
+ * property. We use the BundleContext from the iPOJO bundle context, as a mark for testing, it is obviously,
+ * not recommended.
+ *
+ * These test cases are using Annotation descriptions.
+ */
+public class TestContextInjectionFromAnnotations extends Common {
+
+ @Test
+ public void testFieldInjectionOfComponentBundleContext() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentBundleContextInjectionInField");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testFieldInjectionOfInstanceBundleContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.InstanceBundleContextInjectionInField", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testMethodInjectionOfComponentBundleContext() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentBundleContextInjectionInMethod");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testMethodInjectionOfInstanceBundleContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.InstanceBundleContextInjectionInMethod", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testConstructorInjectionOfComponentBundleContext() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentBundleContextInjectionInConstructor");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testConstructorInjectionOfInstanceBundleContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.InstanceBundleContextInjectionInConstructor", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testInstanceCreatedFromConfiguration() {
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, "from.configuration");
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertNotSame(bc, context);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromXML.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromXML.java
new file mode 100644
index 0000000..2a19492
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestContextInjectionFromXML.java
@@ -0,0 +1,113 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Checks that contexts are correctly injected.
+ * For instance bundle context, we use the 'instance.bundle.context' hidden configuration
+ * property. We use the BundleContext from the iPOJO bundle context, as a mark for testing, it is obviously,
+ * not recommended.
+ *
+ * These test cases are using XML descriptions.
+ */
+public class TestContextInjectionFromXML extends Common {
+
+ @Test
+ public void testFieldInjectionOfComponentBundleContextUsingXML() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Field-Component");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testFieldInjectionOfInstanceBundleContextUsingXML() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Field-Instance", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testMethodInjectionOfComponentBundleContextUsingXML() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Method-Component");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testMethodInjectionOfInstanceBundleContextUsingXML() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Method-Instance", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testConstructorInjectionOfComponentBundleContextUsingXML() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Constructor-Component");
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+ @Test
+ public void testConstructorInjectionOfInstanceBundleContextUsingXML() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("CTX-Constructor-Instance", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingComponentAndInstanceContext.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingComponentAndInstanceContext.java
new file mode 100644
index 0000000..083c2e4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingComponentAndInstanceContext.java
@@ -0,0 +1,128 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Checks that component can retrieve both contexts.
+ * For instance bundle context, we use the 'instance.bundle.context' hidden configuration
+ * property. We use the BundleContext from the iPOJO bundle context, as a mark for testing, it is obviously,
+ * not recommended.
+ *
+ * These test cases are using Annotation descriptions.
+ */
+public class TestInjectingComponentAndInstanceContext extends Common {
+
+ @Test
+ public void testSetterInjectionOfBothContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentWithTwoSetters", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("component");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ context = (BundleContext) check.map().get("instance");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testFieldInjectionOfBothContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentWithTwoFields", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("component");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ context = (BundleContext) check.map().get("instance");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ @Test
+ public void testConstructorInjectionOfBothContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentWithTwoConstructorParams", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("component");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ context = (BundleContext) check.map().get("instance");
+ assertNotNull(context);
+ assertEquals(bc, context);
+ }
+
+ /**
+ * Mix bundle context injection with the default bc injection (legacy).
+ */
+ @Test
+ public void testConstructorInjectionOfThreeContext() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.annotations.ComponentWithThreeConstructorParams", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("component");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ context = (BundleContext) check.map().get("instance");
+ assertNotNull(context);
+ assertEquals(bc, context);
+
+ context = (BundleContext) check.map().get("bc");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingContextAndProperties.java b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingContextAndProperties.java
new file mode 100644
index 0000000..d2f3d5b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInjectingContextAndProperties.java
@@ -0,0 +1,76 @@
+/*
+* 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Checks that component can mix property and context in constructor parameters.
+ *
+ * These test cases are using Annotation descriptions.
+ */
+public class TestInjectingContextAndProperties extends Common {
+
+ @Test
+ public void testWhenPropertyIsFirst() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ configuration.put("message", "hello");
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.mix.MixWithProperties1", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ assertEquals("hello", check.map().get("message"));
+ }
+
+ @Test
+ public void testWhenPropertyIsLast() {
+ BundleContext bc = osgiHelper.getBundle("org.apache.felix.ipojo").getBundleContext();
+ Properties configuration = new Properties();
+ configuration.put("instance.bundle.context", bc);
+ configuration.put("message", "hello");
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".components.mix.MixWithProperties2", configuration);
+
+ CheckService check = ipojoHelper.getServiceObjectByName(CheckService.class, instance.getInstanceName());
+ assertNotNull(check);
+
+ BundleContext context = (BundleContext) check.map().get("context");
+ assertNotNull(context);
+ assertEquals(getTestBundle().getSymbolicName(), context.getBundle().getSymbolicName());
+
+ assertEquals("hello", check.map().get("message"));
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/resources/exam.properties b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/resources/exam.properties
new file mode 100644
index 0000000..d8a500d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-context-injection-test/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml
new file mode 100644
index 0000000..36b2a47
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-declaration-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>5.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.api</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java
new file mode 100644
index 0000000..9668318
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java
@@ -0,0 +1,43 @@
+/*
+ * 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.test.components;
+
+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.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component(name = "hello-service", version = "2.0")
+@Provides
+public class EnglishHelloService implements HelloService {
+
+ @Property("Hello2")
+ private String message;
+
+ @Override
+ public String hello(final String name) {
+ return message + " " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java
new file mode 100644
index 0000000..6d986d2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java
@@ -0,0 +1,43 @@
+/*
+ * 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.test.components;
+
+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.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component(name = "hello-service")
+@Provides
+public class EnglishHelloService2 implements HelloService {
+
+ @Property("Hello")
+ private String message;
+
+ @Override
+ public String hello(final String name) {
+ return message + " " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java
new file mode 100644
index 0000000..57ca670
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java
@@ -0,0 +1,43 @@
+/*
+ * 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.test.components;
+
+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.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component
+@Provides
+public class FrenchHelloService implements HelloService {
+
+ @Property("Bonjour")
+ private String message;
+
+ @Override
+ public String hello(final String name) {
+ return message + " " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java
new file mode 100644
index 0000000..712a4c3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+import javax.xml.parsers.SAXParser;
+
+/**
+ * I intentionally left empty the component name plus the @Provides annotation.
+ * This is just to trigger the component manipulation
+ */
+@Component
+public class GermanHelloService implements HelloService {
+
+ SAXParser parser = null;
+
+ @Override
+ public String hello(final String name) {
+ return "Hallo " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
new file mode 100644
index 0000000..abfff19
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.services;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+public interface HelloService {
+ String hello(String name);
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java
new file mode 100644
index 0000000..775dd07
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java
@@ -0,0 +1,45 @@
+/*
+ * 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.test.declaration;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+ @Override
+ public boolean quiet() {
+ return true;
+ }
+
+
+
+ @Override
+ public List<String> getExtraExports() {
+ // The important thing here is to make sure that this package is in the bundle
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.test.components"
+ );
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java
new file mode 100644
index 0000000..8bda8af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java
@@ -0,0 +1,209 @@
+/*
+ * 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.test.declaration;
+
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.extender.DeclarationBuilderService;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilderException;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import static java.lang.String.format;
+import static junit.framework.Assert.*;
+
+public class TestDeclarationBuilderService extends Common {
+
+ private DeclarationBuilderService builder;
+ private DeclarationHandle handle;
+
+ @Before
+ public void setUp() {
+ builder = osgiHelper.getServiceObject(DeclarationBuilderService.class);
+ }
+
+ @After
+ public void tearDown() {
+ if (handle != null) {
+ handle.retract();
+ }
+ }
+
+ @Test
+ public void testAnonymousInstanceCreation() {
+ handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")
+ .build();
+
+ // When a service is registered, all events are fired synchronously, we
+ // can safely test the declaration binding
+ assertFalse(handle.getStatus().isBound());
+ handle.publish();
+
+ // This test has been already ssen as failed.
+ HelloService hs = osgiHelper.waitForService(HelloService.class, "(factory.name=org.apache.felix.ipojo.runtime" +
+ ".core.test.components.FrenchHelloService)", 1000);
+ assertNotNull(hs);
+ System.out.println("Status: " + handle.getStatus().isBound());
+
+ assertTrue(handle.getStatus().isBound());
+ handle.retract();
+ assertFalse(handle.getStatus().isBound());
+ }
+
+ @Test
+ public void testNamedInstanceCreation() {
+ handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")
+ .name("bonjour-service")
+ .build();
+
+ handle.publish();
+ assertTrue(ipojoHelper.isServiceAvailableByName(HelloService.class.getName(), "bonjour-service"));
+ }
+
+ @Test
+ public void testConfiguredInstanceCreation() {
+ handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")
+ .name("bonjour-service")
+ .configure()
+ .property("message", "Salut")
+ .build();
+
+ handle.publish();
+ assertTrue(ipojoHelper.isServiceAvailableByName(HelloService.class.getName(), "bonjour-service"));
+
+ HelloService service = osgiHelper.getServiceObject(HelloService.class, format("(instance.name=%s)", "bonjour-service"));
+ assertEquals(service.hello("Guillaume"), "Salut Guillaume");
+ }
+
+ @Test
+ public void testVersionedTypeInstanceCreation() {
+ handle = builder.newInstance("hello-service")
+ .version("2.0")
+ .name("hello2")
+ .build();
+
+ handle.publish();
+
+ String filter = format("(instance.name=%s)", "hello2");
+ osgiHelper.waitForService(HelloService.class, filter, 1000);
+ HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);
+ assertEquals(service.hello("Guillaume"), "Hello2 Guillaume");
+ }
+
+ @Test
+ public void testExtensionCreation() {
+ handle = builder.newExtension("test", new EmptyFactoryBuilder());
+
+ handle.publish();
+
+ osgiHelper.waitForService(ExtensionDeclaration.class, null, 1000);
+ }
+
+ @Test
+ public void testTypeCreation() throws Exception {
+
+ handle = builder.newType(germanComponent());
+ handle.publish();
+
+ DeclarationHandle instance = builder.newInstance("german-service")
+ .name("german-hello")
+ .build();
+ instance.publish();
+
+ System.out.println(instance.getStatus().getMessage());
+
+ String filter = format("(instance.name=%s)", "german-hello");
+ osgiHelper.waitForService(HelloService.class, filter, 1000);
+ HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);
+ assertEquals(service.hello("Guillaume"), "Hallo Guillaume");
+
+ instance.retract();
+
+ }
+
+ /*
+ @Test
+ public void testTypeCreationFromAPI() throws Exception {
+ PrimitiveComponentType type = new PrimitiveComponentType()
+ .setClassName("org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService")
+ .setComponentTypeName("german-service")
+ .addService(new Service());
+
+ Element description = type.getFactory().getComponentMetadata();
+ handle = builder.newType(description);
+ handle.publish();
+
+ DeclarationHandle instance = builder.newInstance("german-service")
+ .name("german-hello")
+ .build();
+ instance.publish();
+
+ String filter = format("(instance.name=%s)", "german-hello");
+ osgiHelper.waitForService(HelloService.class, filter, 1000);
+ HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);
+ assertEquals(service.hello("Guillaume"), "Hallo Guillaume");
+
+ instance.retract();
+
+ }
+ */
+
+ private Element germanComponent() {
+ Element component = new Element("component", null);
+ component.addAttribute(new Attribute("name", "german-service"));
+ component.addAttribute(new Attribute("classname", "org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService"));
+ component.addElement(new Element("provides", null));
+ component.addElement(manipulation());
+ return component;
+ }
+
+ private Element manipulation() {
+ Element manipulation = new Element("manipulation", null);
+ manipulation.addAttribute(new Attribute("classname", "org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService"));
+ manipulation.addAttribute(new Attribute("super", "java.lang.Object"));
+
+ Element itf = new Element("interface", null);
+ itf.addAttribute(new Attribute("name", "org.apache.felix.ipojo.runtime.core.test.services.HelloService"));
+ manipulation.addElement(itf);
+
+ Element method = new Element("method", null);
+ method.addAttribute(new Attribute("name", "hello"));
+ method.addAttribute(new Attribute("return", "java.lang.String"));
+ method.addAttribute(new Attribute("arguments", "{java.lang.String}"));
+ method.addAttribute(new Attribute("names", "{name}"));
+ manipulation.addElement(method);
+
+ return manipulation;
+ }
+
+ private static class EmptyFactoryBuilder implements FactoryBuilder {
+ @Override
+ public IPojoFactory build(final BundleContext bundleContext, final Element metadata) throws FactoryBuilderException {
+ return null;
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/pom.xml
new file mode 100644
index 0000000..3474f4c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-external-handlers-test</artifactId>
+ <name>${project.artifactId}</name>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceAndFieldInterceptorHandler.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceAndFieldInterceptorHandler.java
new file mode 100644
index 0000000..23a400d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceAndFieldInterceptorHandler.java
@@ -0,0 +1,131 @@
+/*
+ * 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.externalhandlers.components;
+
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckService;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckServiceHandlerDescription;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+public class CheckServiceAndFieldInterceptorHandler extends PrimitiveHandler implements CheckService {
+
+ ServiceRegistration sr;
+ boolean isValid;
+ int changes = 0;
+ static final String NAMESPACE = "org.apache.felix.ipojo.test.handler.checkservice";
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ private String m_value;
+
+ public void configure(Element metadata, Dictionary configuration) {
+ Element[] meta = metadata.getElements("checkAndSet", NAMESPACE);
+ if(meta == null) { return; }
+ // Get handler props
+ props.put("instance.name", configuration.get("instance.name"));
+ if(configuration.get("csh.simple") != null) { props.put("Simple", configuration.get("csh.simple")); }
+ if(configuration.get("csh.map") != null) {
+ Dictionary m = (Dictionary) configuration.get("csh.map");
+ if (m.size() > 0) {
+ props.put("Map1", m.get("a"));
+ props.put("Map2", m.get("b"));
+ props.put("Map3", m.get("c"));
+ }
+ }
+ props.put("changes", changes);
+
+ getInstanceManager().register(getPojoMetadata().getField("m_foo"), this);
+ m_value = (String) configuration.get("foo");
+
+ }
+
+ public void initializeComponentFactory(ComponentTypeDescription cd, Element metadata) {
+ cd.addProperty(new PropertyDescription("csh.simple", "java.lang.String", null));
+ cd.addProperty(new PropertyDescription("csh.map", "java.util.Dictionary", null));
+ }
+
+ public void start() {
+ if(sr == null) {
+ sr = getInstanceManager().getContext().registerService(CheckService.class.getName(), this, props);
+ }
+ isValid = true;
+ }
+
+ public void stop() {
+ isValid = false;
+ synchronized(this) {
+ if(sr != null) { sr.unregister(); }
+ }
+ }
+
+ public boolean check() {
+ isValid = !isValid;
+ return isValid;
+ }
+
+ public Dictionary<String, Object> getProps() {
+ props.put("foo", m_value);
+ return props;
+ }
+
+ public void stateChanged(int state) {
+ if (sr != null) {
+ changes++;
+ props.put("changes", changes);
+ sr.setProperties(props);
+ }
+ }
+
+ public String getName() {
+ return NAMESPACE;
+ }
+
+ public HandlerDescription getDescription() {
+ return new CheckServiceHandlerDescription(this);
+ }
+
+ @Override
+ public Object onGet(Object pojo, String fieldName, Object value) {
+ if (fieldName.equals("m_foo")) {
+ return m_value;
+ }
+ if (pojo == null) {
+ throw new IllegalStateException("pojo parameter null - FELIX-4072");
+ }
+ return value;
+ }
+
+ @Override
+ public void onSet(Object pojo, String fieldName, Object value) {
+ if (fieldName.equals("m_foo")) {
+ System.out.println("Attempt to set the foo field to " + value);
+ m_value = (String) value;
+ }
+ if (pojo == null) {
+ throw new IllegalStateException("pojo parameter null - FELIX-4072");
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceHandler.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceHandler.java
new file mode 100644
index 0000000..d2d1a70
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/CheckServiceHandler.java
@@ -0,0 +1,106 @@
+/*
+ * 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.externalhandlers.components;
+
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckService;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckServiceHandlerDescription;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+public class CheckServiceHandler extends PrimitiveHandler implements CheckService {
+
+ ServiceRegistration sr;
+ boolean isValid;
+ int changes = 0;
+ static final String NAMESPACE = "org.apache.felix.ipojo.test.handler.checkservice";
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+
+ public void configure(Element metadata, Dictionary configuration) {
+ Element[] meta = metadata.getElements("check", NAMESPACE);
+ if(meta == null) { return; }
+ // Get handler props
+ props.put("instance.name", configuration.get("instance.name"));
+ if(configuration.get("csh.simple") != null) { props.put("Simple", configuration.get("csh.simple")); }
+ if(configuration.get("csh.map") != null) {
+ Dictionary m = (Dictionary) configuration.get("csh.map");
+ if (m.size() > 0) {
+ props.put("Map1", m.get("a"));
+ props.put("Map2", m.get("b"));
+ props.put("Map3", m.get("c"));
+ }
+ }
+ props.put("changes", new Integer(changes));
+
+ }
+
+ public void initializeComponentFactory(ComponentTypeDescription cd, Element metadata) {
+ cd.addProperty(new PropertyDescription("csh.simple", "java.lang.String", null));
+ cd.addProperty(new PropertyDescription("csh.map", "java.util.Dictionary", null));
+ }
+
+ public void start() {
+ if(sr == null) {
+ sr = getInstanceManager().getContext().registerService(CheckService.class.getName(), this, props);
+ }
+ isValid = true;
+ }
+
+ public void stop() {
+ isValid = false;
+ synchronized(this) {
+ if(sr != null) { sr.unregister(); }
+ }
+ }
+
+ public boolean check() {
+ if(isValid) { isValid = false;}
+ else { isValid = true; }
+ return isValid;
+ }
+
+ public Dictionary<String, Object> getProps() {
+ return props;
+ }
+
+ public void stateChanged(int state) {
+ if (sr != null) {
+ changes++;
+ props.put("changes", new Integer(changes));
+ sr.setProperties(props);
+ }
+ }
+
+ public String getName() {
+ return NAMESPACE;
+ }
+
+ public HandlerDescription getDescription() {
+ return new CheckServiceHandlerDescription(this);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/FooProviderType1.java
new file mode 100644
index 0000000..0d2dfb0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/components/FooProviderType1.java
@@ -0,0 +1,74 @@
+/*
+ * 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.externalhandlers.components;
+
+import org.apache.felix.ipojo.runtime.externalhandlers.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ // Update m_foo
+ if (m_foo.equals(VALUE)) {
+ m_foo = VALUE_2;
+ }
+
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", m_bar);
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ int count = 0;
+ p.put("count", count);
+ return p;
+ }
+
+
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return true; }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckService.java
new file mode 100644
index 0000000..916620d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.externalhandlers.services;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Dictionary<String, Object> getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckServiceHandlerDescription.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckServiceHandlerDescription.java
new file mode 100644
index 0000000..fd20286
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/CheckServiceHandlerDescription.java
@@ -0,0 +1,38 @@
+/*
+ * 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.externalhandlers.services;
+
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class CheckServiceHandlerDescription extends HandlerDescription {
+
+ public CheckServiceHandlerDescription(Handler h) {
+ super(h);
+ }
+
+ public Element getHandlerInfo() {
+ Element elem = super.getHandlerInfo();
+ elem.addAttribute(new Attribute("isValid", isValid()+""));
+ return elem;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/FooService.java
new file mode 100644
index 0000000..1ccb16e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/java/org/apache/felix/ipojo/runtime/externalhandlers/services/FooService.java
@@ -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.
+ */
+package org.apache.felix.ipojo.runtime.externalhandlers.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ public static final String VALUE = "my foo is better than yours";
+ public static final String VALUE_2 = "No";
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..0f1f66f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/main/resources/metadata.xml
@@ -0,0 +1,77 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:cs="org.apache.felix.ipojo.test.handler.checkservice">
+ <handler
+ classname="org.apache.felix.ipojo.runtime.externalhandlers.components.CheckServiceHandler"
+ name="check"
+ namespace="org.apache.felix.ipojo.test.handler.checkservice"
+ architecture="false">
+ <controller field="isValid" />
+ </handler>
+
+ <!-- a handler with a field interceptor -->
+ <handler
+ classname="org.apache.felix.ipojo.runtime.externalhandlers.components.CheckServiceAndFieldInterceptorHandler"
+ name="checkAndSet"
+ namespace="org.apache.felix.ipojo.test.handler.checkservice"
+ architecture="false">
+ <controller field="isValid" />
+ </handler>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.externalhandlers.components.FooProviderType1"
+ name="HANDLER-HandlerTester" architecture="true">
+ <cs:check />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.externalhandlers.components.FooProviderType1"
+ name="HANDLER-HandlerWithFieldInterceptorTester" architecture="true">
+ <cs:checkAndSet />
+ <provides/>
+ </component>
+
+
+ <instance name="HandlerTest-2" component="HANDLER-HandlerTester">
+ <property name="csh.simple" value="Simple" />
+ <property name="csh.map">
+ <property name="a" value="a" />
+ <property name="b" value="b" />
+ <property name="c" value="c" />
+ </property>
+ </instance>
+ <instance name="HandlerTest-2-empty" component="HANDLER-HandlerTester">
+ <property name="csh.simple" value="Simple" />
+ <property name="csh.map">
+ <!-- Empty dictionary -->
+ </property>
+ </instance>
+
+ <!-- The handler will be added using the auto handler property -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.externalhandlers.components.FooProviderType1"
+ name="HANDLER-HandlerTesterWO" architecture="true">
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/AutoHandlerTest.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/AutoHandlerTest.java
new file mode 100644
index 0000000..fad6cc3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/AutoHandlerTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.externalhandlers.test;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckServiceHandlerDescription;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class AutoHandlerTest extends Common {
+
+ private static final String ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE = "org.apache.felix.ipojo.handler.auto.primitive";
+
+ ComponentInstance instance;
+
+ ComponentFactory factory;
+
+ @Before
+ public void setUp() {
+ factory = (ComponentFactory) ipojoHelper.getFactory("HANDLER-HandlerTesterWO");
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, "");
+ }
+
+ @After
+ public void tearDown() {
+ if (instance != null) {
+ instance.dispose();
+ }
+ instance = null;
+
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, "");
+
+ }
+
+ @Test
+ public void testRequiredHandlerList() {
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, "");
+
+ factory.stop();
+ factory.restart();
+ factory.start();
+
+ List list = factory.getRequiredHandlers();
+ assertFalse(list.contains("org.apache.felix.ipojo.test.handler.checkservice:check"));
+
+ String v = "org.apache.felix.ipojo.test.handler.checkservice:check";
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, v);
+
+ factory.stop();
+ factory.restart();
+ factory.start();
+
+ list = factory.getRequiredHandlers();
+ assertTrue(list.contains("org.apache.felix.ipojo.test.handler.checkservice:check"));
+
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, "");
+
+ }
+
+
+ @Test
+ public void testInstanceCreation() throws Exception {
+ String v = "org.apache.felix.ipojo.test.handler.checkservice:check";
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, v);
+
+ factory.stop();
+ factory.restart();
+ factory.start();
+
+ instance = factory.createComponentInstance(new Properties());
+ assertEquals(ComponentInstance.VALID, instance.getState());
+
+ HandlerDescription hd = instance.getInstanceDescription().getHandlerDescription(v);
+ assertNotNull(hd);
+ assertTrue(hd instanceof CheckServiceHandlerDescription);
+
+ System.setProperty(ORG_APACHE_FELIX_IPOJO_HANDLER_AUTO_PRIMITIVE, "");
+
+ factory.stop();
+ factory.restart();
+ factory.start();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/Common.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/Common.java
new file mode 100644
index 0000000..bfd9e35
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/Common.java
@@ -0,0 +1,29 @@
+/*
+ * 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.externalhandlers.test;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest{
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerTest.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerTest.java
new file mode 100644
index 0000000..3728187
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.externalhandlers.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.HandlerManagerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.Dumps;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class HandlerTest extends Common {
+
+ ComponentInstance instance;
+
+ @Before
+ public void setUp() {
+ Properties props = new Properties();
+ props.put("instance.name", "HandlerTest-1");
+ props.put("csh.simple", "simple");
+ Properties p = new Properties();
+ p.put("a", "a");
+ p.put("b", "b");
+ p.put("c", "c");
+ props.put("csh.map", p);
+ instance = ipojoHelper.createComponentInstance("HANDLER-HandlerTester", props);
+ }
+
+ @Test
+ public void testConfiguration1() {
+ // Check the availability of CheckService
+ String name = "HandlerTest-1";
+ ServiceReference sr = null;
+ ServiceReference[] refs = null;
+ String filter = "(" + "instance.name" + "=" + name + ")";
+ refs = osgiHelper.getServiceReferences(CheckService.class.getName(), filter);
+ if (refs != null) {
+ sr = refs[0];
+ }
+
+ assertNotNull("Check the check service availability", sr);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(sr);
+ Dictionary<String, Object> p = cs.getProps();
+ assertEquals("Assert 'simple' equality", p.get("Simple"), "simple");
+ assertEquals("Assert 'a' equality", p.get("Map1"), "a");
+ assertEquals("Assert 'b' equality", p.get("Map2"), "b");
+ assertEquals("Assert 'c' equality", p.get("Map3"), "c");
+ }
+
+ @Test
+ public void testConfiguration2() {
+ // Check the availability of CheckService
+ String name = "HandlerTest-2";
+ ServiceReference sr = null;
+ ServiceReference[] refs = null;
+ String filter = "(" + "instance.name" + "=" + name + ")";
+
+ refs = osgiHelper.getServiceReferences(CheckService.class.getName(), filter);
+
+ if (refs != null) {
+ sr = refs[0];
+ }
+ assertNotNull("Check the check service availability", sr);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(sr);
+ Dictionary<String, Object> p = cs.getProps();
+ assertEquals("Assert 'simple' equality", p.get("Simple"), "Simple");
+ assertEquals("Assert 'a' equality", p.get("Map1"), "a");
+ assertEquals("Assert 'b' equality", p.get("Map2"), "b");
+ assertEquals("Assert 'c' equality", p.get("Map3"), "c");
+ }
+
+ @Test
+ public void testConfiguration3() {
+ // Check the availability of CheckService
+ String name = "HandlerTest-2-empty";
+ ServiceReference sr = null;
+ ServiceReference[] refs = null;
+ String filter = "(" + "instance.name" + "=" + name + ")";
+ refs = osgiHelper.getServiceReferences(CheckService.class.getName(), filter);
+ if (refs != null) {
+ sr = refs[0];
+ }
+ assertNotNull("Check the check service availability", sr);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(sr);
+ Dictionary<String, Object> p = cs.getProps();
+ assertEquals("Assert 'simple' equality", p.get("Simple"), "Simple");
+ assertEquals("Size of p", 3, p.size()); // instance name, simple and changes.
+
+ cs = null;
+ }
+
+ @Test
+ public void testLifecycle() {
+ // Check the availability of CheckService
+ String name = "HandlerTest-1";
+ ServiceReference sr = null;
+ ServiceReference[] refs = null;
+ String filter = "(" + "instance.name" + "=" + name + ")";
+ refs = osgiHelper.getServiceReferences(CheckService.class.getName(), filter);
+ if (refs != null) {
+ sr = refs[0];
+ }
+ assertNotNull("Check the check service availability", sr);
+
+ ServiceReference sr_arch = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "HandlerTest-1");
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(sr_arch);
+
+ System.out.println("===");
+ Dumps.dumpArchitectures(context);
+ assertEquals("Check instance validity - 0", arch.getInstanceDescription().getState(), ComponentInstance.VALID);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(sr);
+ Dictionary<String, Object> p = cs.getProps();
+ Integer changes = (Integer) p.get("changes");
+ assertNotNull("Check changes no null", changes);
+ assertEquals("Changes changes 1 (" + changes + ")", changes.intValue(), 1);
+ assertEquals("Check instance validity - 1", arch.getInstanceDescription().getState(), ComponentInstance.VALID);
+ cs.check();
+ p = cs.getProps();
+ changes = (Integer) p.get("changes");
+ assertEquals("Changes changes 2 (" + changes + ")", changes.intValue(), 2);
+ assertEquals("Check instance validity - 2", arch.getInstanceDescription().getState(), ComponentInstance.INVALID);
+ cs.check();
+ p = cs.getProps();
+ changes = (Integer) p.get("changes");
+ assertEquals("Changes changes 3 (" + changes + ")", changes.intValue(), 3);
+ assertEquals("Check instance validity - 3", arch.getInstanceDescription().getState(), ComponentInstance.VALID);
+ cs.check();
+ p = cs.getProps();
+ changes = (Integer) p.get("changes");
+ assertEquals("Changes changes 4 (" + changes + ")", changes.intValue(), 4);
+ assertEquals("Check instance validity - 4", arch.getInstanceDescription().getState(), ComponentInstance.INVALID);
+ }
+
+ @Test
+ public void testAvailability() {
+ String name = "HandlerTest-1";
+ ServiceReference sr = null;
+ ServiceReference[] refs = null;
+ String filter = "(" + "instance.name" + "=" + name + ")";
+ refs = osgiHelper.getServiceReferences(CheckService.class.getName(), filter);
+
+ if (refs != null) {
+ sr = refs[0];
+ }
+ assertNotNull("Check the check service availability", sr);
+
+ ServiceReference sr_arch = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "HandlerTest-1");
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(sr_arch);
+ assertEquals("Check validity", arch.getInstanceDescription().getState(), ComponentInstance.VALID);
+
+ // Kill the handler factory
+ HandlerManagerFactory f = (HandlerManagerFactory) ipojoHelper.getHandlerFactory("check");
+ f.stop();
+
+ boolean av = ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "HandlerTest-1");
+ assertFalse("Check the check service unavailability", av);
+
+ boolean av2 = ipojoHelper.isServiceAvailableByName(Architecture.class.getName(), "HandlerTest-1");
+ assertFalse("Check the architecture unavailability", av2);
+
+ // The instance is disposed, restart the handler
+ f.start();
+
+ Properties props = new Properties();
+ props.put("instance.name", "HandlerTest-1");
+ props.put("csh.simple", "simple");
+ Properties p = new Properties();
+ p.put("a", "a");
+ p.put("b", "b");
+ p.put("c", "c");
+ props.put("csh.map", p);
+ instance = ipojoHelper.createComponentInstance("HANDLER-HandlerTester", props);
+
+ sr = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "HandlerTest-1");
+ assertNotNull("Check the check service availability - 2", sr);
+
+ sr_arch = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "HandlerTest-1");
+ arch = (Architecture) osgiHelper.getRawServiceObject(sr_arch);
+ assertEquals("Check validity - 2", arch.getInstanceDescription().getState(), ComponentInstance.VALID);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerWithFieldInterceptorTest.java b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerWithFieldInterceptorTest.java
new file mode 100644
index 0000000..cece611
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-external-handlers-test/src/test/java/org/apache/felix/ipojo/runtime/externalhandlers/test/HandlerWithFieldInterceptorTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.externalhandlers.test;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.HandlerManagerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.CheckService;
+import org.apache.felix.ipojo.runtime.externalhandlers.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.Dumps;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class HandlerWithFieldInterceptorTest extends Common {
+
+
+ ComponentInstance instance;
+
+ @Before
+ public void setUp() {
+ Properties props = new Properties();
+ props.put("instance.name", "HandlerTest-1");
+ props.put("csh.simple", "simple");
+ Properties p = new Properties();
+ p.put("a", "a");
+ p.put("b", "b");
+ p.put("c", "c");
+ props.put("csh.map", p);
+ props.put("foo", FooService.VALUE);
+ instance = ipojoHelper.createComponentInstance("HANDLER-HandlerWithFieldInterceptorTester", props);
+ }
+
+ @Test
+ public void testFieldInterception() {
+ // Check the availability of CheckService
+ String name = "HandlerTest-1";
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), name);
+ assertNotNull("Check the check service availability", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Dictionary<String, Object> p = cs.getProps();
+ assertEquals("Assert 'simple' equality", p.get("Simple"), "simple");
+ assertEquals("Assert 'a' equality", p.get("Map1"), "a");
+ assertEquals("Assert 'b' equality", p.get("Map2"), "b");
+ assertEquals("Assert 'c' equality", p.get("Map3"), "c");
+
+ assertEquals("check foo value", FooService.VALUE, cs.getProps().get("foo"));
+
+ // Change value.
+
+ ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), name);
+ assertNotNull("Check the foo service availability", ref2);
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref2);
+
+ fs.foo(); // This trigger the changes.
+
+ assertEquals("check foo value", FooService.VALUE_2, cs.getProps().get("foo"));
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-factory-test/pom.xml
new file mode 100644
index 0000000..c545497
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-factory-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FiveInstances.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FiveInstances.java
new file mode 100644
index 0000000..26484c2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FiveInstances.java
@@ -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.felix.ipojo.runtime.core.components;
+
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.runtime.core.services.NoService;
+
+@Component(name="FiveInstances")
+public class FiveInstances implements NoService {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..22059a8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..c52415f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoInstances.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoInstances.java
new file mode 100644
index 0000000..97c9518
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NoInstances.java
@@ -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.felix.ipojo.runtime.core.components;
+
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.runtime.core.services.NoService;
+
+@Component(name="NoInstances")
+public class NoInstances implements NoService {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/OneDuplicateInstance.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/OneDuplicateInstance.java
new file mode 100644
index 0000000..8bf63c2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/OneDuplicateInstance.java
@@ -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.felix.ipojo.runtime.core.components;
+
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.runtime.core.services.NoService;
+
+@Component(name="OneDuplicateInstance")
+public class OneDuplicateInstance implements NoService {
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ReconfigurableSimpleType.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ReconfigurableSimpleType.java
new file mode 100644
index 0000000..04f5def
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ReconfigurableSimpleType.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+public class ReconfigurableSimpleType {
+
+
+ private String prop; // Property.
+
+ private String x; // Property.
+
+ boolean controller;
+
+ public void start () {
+ if (prop == null || prop.equals("KO")) {
+ throw new IllegalStateException("Bad Configuration : " + prop);
+ }
+
+ if (x == null) {
+ throw new IllegalStateException("x is null");
+ }
+
+ System.out.println("OK !!!!");
+ }
+
+ public void setX(String v) {
+ x = v;
+ }
+
+ public void setProp(String p) {
+ prop = p;
+ if (prop == null || prop.equals("KO")) {
+ controller = false;
+ } else {
+ controller = true;
+ System.out.println("OK !!!!");
+ }
+ }
+
+ public void setController(boolean p) {
+ if (p) {
+ System.out.println("OK !!!!");
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleType.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleType.java
new file mode 100644
index 0000000..80b590e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleType.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+public class SimpleType {
+
+ private boolean m_controller;
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/NoService.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/NoService.java
new file mode 100644
index 0000000..69cec05
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/NoService.java
@@ -0,0 +1,23 @@
+/*
+ * 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.services;
+
+public interface NoService {
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..ee42f70
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/main/resources/metadata.xml
@@ -0,0 +1,174 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <!-- Simple provider -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Factories-FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Provider providing 2 services -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="Factories-FooBarProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Provider with dynamic property -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="Factories-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2" mandatory="true"/>
+ <property name="boolean" field="boolProp" value="false" mandatory="true"/>
+ <property name="string" field="strProp" value="foo" mandatory="true"/>
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}" mandatory="true"/>
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}" mandatory="true"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="Factories-FooProviderType-Dynopt" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2"/>
+ <property name="boolean" field="boolProp" value="false"/>
+ <property name="string" field="strProp" value="foo"/>
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}"/>
+ <property name="intAProp" field="intAProp" value="{ 1,2,3}"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Factories-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2" mandatory="true" />
+ <property name="long" type="long" value="40" mandatory="true"/>
+ <property name="string" type="java.lang.String" value="foo" mandatory="true"/>
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" mandatory="true" />
+ <property name="intAProp" type="int[]" value="{1,2,3}" mandatory="true"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Factories-FooProviderType-2opt" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2"/>
+ <property name="long" type="long" value="40"/>
+ <property name="string" type="java.lang.String" value="foo"/>
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}" />
+ <property name="intAProp" type="int[]" value="{1,2,3}"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="Factories-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" mandatory="true"/>
+ <property name="boolean" field="boolProp" mandatory="true"/>
+ <property name="string" field="strProp" mandatory="true"/>
+ <property name="strAProp" field="strAProp" mandatory="true"/>
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" mandatory="true"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="Factories-FooProviderType-Dyn2opt" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" />
+ <property name="boolean" field="boolProp"/>
+ <property name="string" field="strProp"/>
+ <property name="strAProp" field="strAProp"/>
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Factories-FooProviderType-3" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" mandatory="true"/>
+ <property name="bar" field="m_bar" mandatory="true"/>
+ <property name="baz" type="java.lang.String" mandatory="true"/>
+ </provides>
+ <properties propagation="true">
+ <property name="foo" field="m_foo" mandatory="true"/>
+ <property name="bar" field="m_bar" mandatory="true"/>
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="Factories-FooProviderType-3opt" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo"/>
+ <property name="bar" field="m_bar"/>
+ <property name="baz" type="java.lang.String"/>
+ </provides>
+ <properties propagation="true">
+ <property name="foo" field="m_foo"/>
+ <property name="bar" field="m_bar"/>
+ </properties>
+ </component>
+
+ <!-- type & instance used to check instance lifecycle against factory validation & invalidation -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.SimpleType" architecture="true">
+ <controller field="m_controller"/>
+ </component>
+ <instance component="org.apache.felix.ipojo.runtime.core.components.SimpleType" name="SimpleInstance"/>
+
+ <!-- check that instance state is recomputed after reconfiguration -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType" architecture="true">
+ <properties>
+ <property name="prop" field="prop"/>
+ <property name="x" method="setX" value="x"/>
+ </properties>
+ <callback transition="validate" method="start"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType"
+ name="org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType2"
+ architecture="true" immediate="true">
+ <properties>
+ <property name="prop" method="setProp"/>
+ <property name="x" method="setX" value="x"/>
+ </properties>
+ <controller field="controller"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType"
+ name="org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType3"
+ architecture="true" immediate="true">
+ <properties>
+ <property name="controller" method="setController" field="controller"/>
+ <property name="x" method="setX" value="x"/>
+ </properties>
+ <controller field="controller"/>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..069dc88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+import org.ow2.chameleon.testing.helpers.ConfigAdminHelper;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ public static int UPDATE_WAIT_TIME = 2000;
+ public ConfigAdminHelper caHelper = null;
+ public ConfigurationAdmin admin;
+
+ public void grace() {
+ TimeUtils.grace(UPDATE_WAIT_TIME);
+ }
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Before
+ public void initializeConfigAdmin() {
+ caHelper = new ConfigAdminHelper(bc);
+ admin = caHelper.getConfigurationAdmin();
+ caHelper.deleteAllConfigurations();
+ }
+
+ @After
+ public void stoppingConfigAdmin() {
+ caHelper.deleteAllConfigurations();
+ caHelper.dispose();
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComponentDesc.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComponentDesc.java
new file mode 100644
index 0000000..1561e58
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestComponentDesc.java
@@ -0,0 +1,345 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Arrays;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Check component type description.
+ */
+public class TestComponentDesc extends Common {
+
+ ServiceReference sr_fooProvider1;
+ ServiceReference sr_fooProvider2;
+ ServiceReference sr_fooProviderDyn2;
+ ServiceReference sr_fooProvider3;
+ ServiceReference sr_foobarProvider;
+
+ Factory fooProvider1;
+ Factory fooProvider2;
+ Factory fooProviderDyn2;
+ Factory fooProvider3;
+ Factory foobarProvider;
+
+ @Before
+ public void setUp() {
+
+ sr_fooProvider1 = osgiHelper.getServiceReferenceByPID(Factory.class, "Factories-FooProviderType-1");
+ sr_fooProvider2 = osgiHelper.getServiceReferenceByPID(Factory.class, "Factories-FooProviderType-2");
+ sr_fooProviderDyn2 = osgiHelper.getServiceReferenceByPID(Factory.class, "Factories-FooProviderType-Dyn2");
+ sr_fooProvider3 = osgiHelper.getServiceReferenceByPID(Factory.class, "Factories-FooProviderType-3");
+ sr_foobarProvider = osgiHelper.getServiceReferenceByPID(Factory.class, "Factories-FooBarProviderType-1");
+
+ fooProvider1 = ipojoHelper.getFactory("Factories-FooProviderType-1");
+ fooProvider2 = ipojoHelper.getFactory("Factories-FooProviderType-2");
+ fooProviderDyn2 = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+ fooProvider3 = ipojoHelper.getFactory("Factories-FooProviderType-3");
+ foobarProvider = ipojoHelper.getFactory("Factories-FooBarProviderType-1");
+ }
+
+ /**
+ * Check simple providing.
+ */
+ @Test
+ public void testFooProvider1() {
+ // Test SR properties
+// String impl = (String) sr_fooProvider1.getProperty("component.class");
+// assertEquals("Check component.class", impl, "org.apache.felix.ipojo.test.scenarios.component.FooProviderType1");
+
+ String[] specs = (String[]) sr_fooProvider1.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check component.providedServiceSpecifications length", specs.length, 1);
+ assertEquals("Check component.providedServiceSpecifications", FooService.class.getName(), specs[0]);
+
+ PropertyDescription[] pd = (PropertyDescription[]) sr_fooProvider1.getProperty("component.properties");
+ assertEquals("Check component.properties length", pd.length, 0);
+
+ // Test factory
+ assertEquals("Check factory name", fooProvider1.getName(), "Factories-FooProviderType-1");
+ Element cd = fooProvider1.getDescription();
+
+// assertEquals("Check implementation class ", cd.getAttribute("implementation-class"), impl);
+
+ Element[] specs2 = cd.getElements("provides");
+ assertEquals("Check specs length", specs2.length, 1);
+ assertEquals("Check specs", FooService.class.getName(), specs2[0].getAttribute("specification"));
+
+ Element[] pd2 = cd.getElements("property");
+ assertNull("Check props null", pd2);
+
+ // Check Description equality
+ ComponentTypeDescription desc = (ComponentTypeDescription) sr_fooProvider1.getProperty("component.description");
+ assertNotNull("check description equality", desc);
+ }
+
+ /**
+ * Check component properties.
+ */
+ @Test
+ public void testFooProvider2() {
+ // Test SR properties
+// String impl = (String) sr_fooProvider2.getProperty("component.class");
+// assertEquals("Check component.class", impl, "org.apache.felix.ipojo.test.scenarios.component.FooProviderType1");
+
+ String[] specs = (String[]) sr_fooProvider2.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check component.providedServiceSpecifications length", specs.length, 1);
+ assertEquals("Check component.providedServiceSpecifications", FooService.class.getName(), specs[0]);
+
+ PropertyDescription[] pd = (PropertyDescription[]) sr_fooProvider2.getProperty("component.properties");
+ assertEquals("Check component.properties length", pd.length, 5);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "int", pd[0].getName());
+ assertEquals("Check component.properties type [" + 0 + "]", "int", pd[0].getType());
+ assertEquals("Check component.properties value [" + 0 + "]", "2", pd[0].getValue());
+
+ assertEquals("Check component.properties name [" + 1 + "]", "long", pd[1].getName());
+ assertEquals("Check component.properties type [" + 1 + "]", "long", pd[1].getType());
+ assertEquals("Check component.properties value [" + 1 + "]", "40", pd[1].getValue());
+
+ assertEquals("Check component.properties name [" + 2 + "]", "string", pd[2].getName());
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd[2].getType());
+ assertEquals("Check component.properties value [" + 2 + "]", "foo", pd[2].getValue());
+
+ assertEquals("Check component.properties name [" + 3 + "]", "strAProp", pd[3].getName());
+ assertEquals("Check component.properties type [" + 3 + "]", "java.lang.String[]", pd[3].getType());
+
+ assertEquals("Check component.properties name [" + 4 + "]", "intAProp", pd[4].getName());
+ assertEquals("Check component.properties type [" + 4 + "]", "int[]", pd[4].getType());
+
+ // Test factory
+ assertEquals("Check factory name", fooProvider2.getName(), "Factories-FooProviderType-2");
+ Element cd = fooProvider2.getDescription();
+
+// assertEquals("Check implementation class ", cd.getAttribute("implementation-class"), impl);
+
+ Element[] specs2 = cd.getElements("provides");
+ assertEquals("Check specs length", specs2.length, 1);
+ assertEquals("Check specs", FooService.class.getName(), specs2[0].getAttribute("specification"));
+
+ Element[] pd2 = cd.getElements("property");
+ assertEquals("Check props length", pd2.length, 5);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "int", pd2[0].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 0 + "]", "int", pd2[0].getAttribute("type"));
+ assertEquals("Check component.properties value [" + 0 + "]", "2", pd2[0].getAttribute("value"));
+
+ assertEquals("Check component.properties name [" + 1 + "]", "long", pd2[1].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 1 + "]", "long", pd2[1].getAttribute("type"));
+ assertEquals("Check component.properties value [" + 1 + "]", "40", pd2[1].getAttribute("value"));
+
+ assertEquals("Check component.properties name [" + 2 + "]", "string", pd2[2].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd2[2].getAttribute("type"));
+ assertEquals("Check component.properties value [" + 2 + "]", "foo", pd2[2].getAttribute("value"));
+
+ assertEquals("Check component.properties name [" + 3 + "]", "strAProp", pd2[3].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 3 + "]", "java.lang.String[]", pd2[3].getAttribute("type"));
+
+ assertEquals("Check component.properties name [" + 4 + "]", "intAProp", pd2[4].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 4 + "]", "int[]", pd2[4].getAttribute("type"));
+
+ // Check Description equality
+ ComponentTypeDescription desc = (ComponentTypeDescription) sr_fooProvider2.getProperty("component.description");
+ assertNotNull("check description equality", desc);
+
+ // Check that we have the complete metadata
+ assertNotNull(fooProvider2.getComponentMetadata());
+ }
+
+ /**
+ * Check component properties (dynamic).
+ */
+ @Test
+ public void testFooProviderDyn2() {
+ // Test SR properties
+// String impl = (String) sr_fooProviderDyn2.getProperty("component.class");
+// assertEquals("Check component.class", impl, "org.apache.felix.ipojo.test.scenarios.component.FooProviderTypeDyn2");
+
+ String[] specs = (String[]) sr_fooProviderDyn2.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check component.providedServiceSpecifications length", specs.length, 1);
+ assertEquals("Check component.providedServiceSpecifications", FooService.class.getName(), specs[0]);
+
+ PropertyDescription[] pd = (PropertyDescription[]) sr_fooProviderDyn2.getProperty("component.properties");
+ assertEquals("Check component.properties length", pd.length, 5);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "int", pd[0].getName());
+ assertEquals("Check component.properties type [" + 0 + "]", "int", pd[0].getType());
+ assertEquals("Check component.properties value [" + 0 + "]", "4", pd[0].getValue());
+
+ assertEquals("Check component.properties name [" + 1 + "]", "boolean", pd[1].getName());
+ assertEquals("Check component.properties type [" + 1 + "]", "boolean", pd[1].getType());
+
+ assertEquals("Check component.properties name [" + 2 + "]", "string", pd[2].getName());
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd[2].getType());
+
+ assertEquals("Check component.properties name [" + 3 + "]", "strAProp", pd[3].getName());
+ assertEquals("Check component.properties type [" + 3 + "]", "java.lang.String[]", pd[3].getType());
+
+ assertEquals("Check component.properties name [" + 4 + "]", "intAProp", pd[4].getName());
+ assertEquals("Check component.properties type [" + 4 + "]", "int[]", pd[4].getType());
+
+ // Test factory
+ assertEquals("Check factory name", fooProviderDyn2.getName(), "Factories-FooProviderType-Dyn2");
+ Element cd = fooProviderDyn2.getDescription();
+
+// assertEquals("Check implementation class ", cd.getAttribute("implementation-class"), impl);
+
+ Element[] specs2 = cd.getElements("provides");
+ assertEquals("Check specs length", specs2.length, 1);
+ assertEquals("Check specs", FooService.class.getName(), specs2[0].getAttribute("specification"));
+
+ Element[] pd2 = cd.getElements("property");
+ assertEquals("Check props length", pd2.length, 5);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "int", pd2[0].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 0 + "]", "int", pd2[0].getAttribute("type"));
+ assertEquals("Check component.properties value [" + 0 + "]", "4", pd2[0].getAttribute("value"));
+
+ assertEquals("Check component.properties name [" + 1 + "]", "boolean", pd2[1].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 1 + "]", "boolean", pd2[1].getAttribute("type"));
+
+ assertEquals("Check component.properties name [" + 2 + "]", "string", pd2[2].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd2[2].getAttribute("type"));
+
+ assertEquals("Check component.properties name [" + 3 + "]", "strAProp", pd2[3].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 3 + "]", "java.lang.String[]", pd2[3].getAttribute("type"));
+
+ assertEquals("Check component.properties name [" + 4 + "]", "intAProp", pd2[4].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 4 + "]", "int[]", pd2[4].getAttribute("type"));
+
+ // Check Description equality
+ ComponentTypeDescription desc = (ComponentTypeDescription) sr_fooProviderDyn2.getProperty("component.description");
+ assertNotNull("check description equality", desc);
+
+ // Check that we have the complete metadata
+ assertNotNull(fooProvider2.getComponentMetadata());
+ }
+
+ /**
+ * Check component properties.
+ */
+ @Test
+ public void testFooProvider3() {
+ // Test SR properties
+// String impl = (String) sr_fooProvider3.getProperty("component.class");
+// assertEquals("Check component.class", impl, "org.apache.felix.ipojo.test.scenarios.component.FooProviderType1");
+
+ String[] specs = (String[]) sr_fooProvider3.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check component.providedServiceSpecifications length", specs.length, 1);
+ assertEquals("Check component.providedServiceSpecifications", FooService.class.getName(), specs[0]);
+
+ PropertyDescription[] pd = (PropertyDescription[]) sr_fooProvider3.getProperty("component.properties");
+ assertEquals("Check component.properties length (" + pd.length +")", pd.length, 3);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "foo", pd[0].getName());
+
+ assertEquals("Check component.properties name [" + 1 + "]", "bar", pd[1].getName());
+
+ assertEquals("Check component.properties name [" + 2 + "]", "baz", pd[2].getName());
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd[2].getType());
+
+ // Test factory
+ assertEquals("Check factory name", fooProvider3.getName(), "Factories-FooProviderType-3");
+ Element cd = fooProvider3.getDescription();
+
+// assertEquals("Check implementation class ", cd.getAttribute("implementation-class"), impl);
+
+ Element[] specs2 = cd.getElements("provides");
+ assertEquals("Check specs length", specs2.length, 1);
+ assertEquals("Check specs", FooService.class.getName(), specs2[0].getAttribute("specification"));
+
+ Element[] pd2 = cd.getElements("property");
+ assertEquals("Check props length", pd2.length, 3);
+
+ assertEquals("Check component.properties name [" + 0 + "]", "foo", pd2[0].getAttribute("name"));
+
+ assertEquals("Check component.properties name [" + 1 + "]", "bar", pd2[1].getAttribute("name"));
+
+ assertEquals("Check component.properties name [" + 2 + "]", "baz", pd2[2].getAttribute("name"));
+ assertEquals("Check component.properties type [" + 2 + "]", "java.lang.String", pd2[2].getAttribute("type"));
+
+ // Check Description equality
+ ComponentTypeDescription desc = (ComponentTypeDescription) sr_fooProvider3.getProperty("component.description");
+ assertNotNull("check description equality", desc);
+ }
+
+ /**
+ * Test two services provider.
+ */
+ @Test
+ public void testFooBar() {
+ // Test SR properties
+// String impl = (String) sr_foobarProvider.getProperty("component.class");
+// assertEquals("Check component.class", impl, "org.apache.felix.ipojo.test.scenarios.component.FooBarProviderType1");
+
+ String[] specs = (String[]) sr_foobarProvider.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check component.providedServiceSpecifications length", specs.length, 2);
+
+ assertContains("Check component.providedServiceSpecifications 1", specs, FooService.class.getName());
+ assertContains("Check component.providedServiceSpecifications 2", specs, BarService.class.getName());
+
+ PropertyDescription[] pd = (PropertyDescription[]) sr_foobarProvider.getProperty("component.properties");
+ assertEquals("Check component.properties length", pd.length, 0);
+
+ // Test factory
+ assertEquals("Check factory name", foobarProvider.getName(), "Factories-FooBarProviderType-1");
+ Element cd = foobarProvider.getDescription();
+
+// assertEquals("Check implementation class ", cd.getAttribute("implementation-class"), impl);
+
+ Element[] specs2 = cd.getElements("provides");
+ assertEquals("Check specs length", specs2.length, 2);
+ assertTrue("Check specs", containsSpecification(FooService.class.getName(), specs2));
+ assertTrue("Check specs", containsSpecification(BarService.class.getName(), specs2));
+
+ Element[] pd2 = cd.getElements("property");
+ assertNull("Check props null", pd2);
+
+ // Check Description equality
+ ComponentTypeDescription desc = (ComponentTypeDescription) sr_foobarProvider.getProperty("component.description");
+ assertNotNull("check description equality", desc);
+
+ // Check that we have the complete metadata
+ assertNotNull(foobarProvider.getComponentMetadata());
+ }
+
+ private boolean containsSpecification(String value, Element[] array) {
+ for (int i = 0; array != null && i < array.length; i++) {
+ if (array[i] != null && array[i].containsAttribute("specification") && array[i].getAttribute("specification").equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigAdmin.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigAdmin.java
new file mode 100644
index 0000000..3ba1318
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigAdmin.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * Check configuration admin reconfiguration.
+ */
+public class TestConfigAdmin extends Common {
+
+ /**
+ * Check creation.
+ */
+ @Test
+ public void testCreation() throws IOException, InterruptedException {
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class, null);
+ Configuration conf = admin.createFactoryConfiguration("Factories-FooProviderType-2", "?");
+
+ Dictionary<String, Object> p = new Hashtable<String, Object>();
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ conf.update(p);
+ grace();
+
+ String pid = conf.getPid();
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+ assertNotNull("Check instance creation", ref);
+
+ // Deletion of the configuration
+ conf.delete();
+ grace();
+
+ boolean av = ipojoHelper.isServiceAvailableByName(FooService.class.getName(), pid);
+ assertFalse("Check instance deletion", av);
+ }
+
+ /**
+ * Check creation (push String).
+ */
+ @Test
+ public void testCreationString() throws IOException, InterruptedException {
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class, null);
+ Configuration conf = admin.createFactoryConfiguration("Factories-FooProviderType-2", "?");
+
+ Dictionary<String, Object> p = new Hashtable<String, Object>();
+ p.put("int", "3");
+ p.put("long", "42");
+ p.put("string", "absdir");
+ p.put("strAProp", "{a}");
+ p.put("intAProp", "{1,2}");
+
+ conf.update(p);
+ grace();
+
+ String pid = conf.getPid();
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+
+ assertNotNull("Check instance creation", ref);
+
+ conf.delete();
+ grace();
+
+ boolean av = ipojoHelper.isServiceAvailableByName(FooService.class.getName(), pid);
+ assertFalse("Check instance deletion", av);
+ }
+
+ /**
+ * Check update and delete.
+ */
+ @Test
+ public void testUpdate() throws IOException, InterruptedException {
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class, null);
+ Configuration conf = admin.createFactoryConfiguration("Factories-FooProviderType-2", "?");
+
+ Dictionary<String, Object> p = new Hashtable<String, Object>();
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ conf.update(p);
+ grace();
+
+ String pid = conf.getPid();
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+
+ assertNotNull("Check instance creation", ref);
+
+ p.put("int", 4);
+ conf.update(p);
+ grace();
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+ Integer test = (Integer) ref.getProperty("int");
+ assertEquals("Check instance modification", 4, test.intValue());
+
+ conf.delete();
+ grace();
+
+ boolean av = ipojoHelper.isServiceAvailableByName(FooService.class.getName(), pid);
+ assertFalse("Check instance deletion", av);
+ }
+
+ /**
+ * Check update and delete.
+ * (Push String).
+ */
+ @Test
+ public void testUpdateString() throws IOException, InterruptedException {
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class, null);
+ Configuration conf = admin.createFactoryConfiguration("Factories-FooProviderType-2", "?");
+
+ Dictionary<String, Object> p = new Hashtable<String, Object>();
+ p.put("int", "3");
+ p.put("long", "42");
+ p.put("string", "absdir");
+ p.put("strAProp", "{a}");
+ p.put("intAProp", "{1,2}");
+
+ conf.update(p);
+ grace();
+
+ String pid = conf.getPid();
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+ assertNotNull("Check instance creation", ref);
+ p.put("int", new Integer("4"));
+ conf.update(p);
+ grace();
+
+ ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), pid);
+ Integer test = (Integer) ref.getProperty("int");
+ assertEquals("Check instance modification", 4, test.intValue());
+ conf.delete();
+ grace();
+
+ boolean av = ipojoHelper.isServiceAvailableByName(FooService.class.getName(), pid);
+ assertFalse("Check instance deletion", av);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFactoryProperties.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFactoryProperties.java
new file mode 100644
index 0000000..547a6b0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestFactoryProperties.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TestFactoryProperties extends Common {
+
+ @Test
+ public void testSimpleExposition() {
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "Factories-FooProviderType-1");
+ assertNotNull("The factory is available", ref1);
+ String[] spec = (String[]) ref1.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check array length", spec.length, 1);
+ assertEquals("Check spec", spec[0], FooService.class.getName());
+ }
+
+ @Test
+ public void testDoubleExposition() {
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "Factories-FooBarProviderType-1");
+ assertNotNull("The factory is available", ref1);
+ String[] spec = (String[]) ref1.getProperty("component.providedServiceSpecifications");
+ assertEquals("Check array length", spec.length, 2);
+ assertContains("Check spec 1", spec, FooService.class.getName());
+ assertContains("Check spec 2", spec, BarService.class.getName());
+ }
+
+ @Test
+ public void testProps() {
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "Factories-FooProviderType-Dyn2");
+ assertNotNull("The factory is available", ref1);
+ PropertyDescription[] pd = (PropertyDescription[]) ref1.getProperty("component.properties");
+ assertEquals("Check property list size", pd.length, 5);
+
+ //P0
+ assertEquals("0) Check name", "int", pd[0].getName());
+ assertEquals("0) Check type", "int", pd[0].getType());
+ assertEquals("0) Check value", "4", pd[0].getValue());
+
+ //P1
+ assertEquals("1) Check name", "boolean", pd[1].getName());
+ assertEquals("1) Check type", "boolean", pd[1].getType());
+ assertNull("1) Check value", pd[1].getValue());
+
+ //P2
+ assertEquals("2) Check name", "string", pd[2].getName());
+ assertEquals("2) Check type", String.class.getName(), pd[2].getType());
+ assertNull("2) Check value", pd[2].getValue());
+
+ //P3
+ assertEquals("3) Check name", "strAProp", pd[3].getName());
+ assertEquals("3) Check type", "java.lang.String[]", pd[3].getType());
+ assertNull("3) Check value", pd[3].getValue());
+
+ //P4
+ assertEquals("4) Check name", "intAProp", pd[4].getName());
+ assertEquals("4) Check type", "int[]", pd[4].getType());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInstances.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInstances.java
new file mode 100644
index 0000000..f2978c9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInstances.java
@@ -0,0 +1,176 @@
+/*
+ * 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;
+
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static junit.framework.Assert.*;
+
+/**
+ * Checks the retrieval of instances and instance names from the Factory.
+ */
+public class TestInstances extends Common {
+
+ @Test
+ public void testNoInstances() {
+ Factory factory = ipojoHelper.getFactory("NoInstances");
+ assertNotNull(factory);
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(0, factory.getInstancesNames().size());
+ assertEquals(0, factory.getInstances().size());
+ }
+
+ @Test
+ public void testOneDuplicateInstance() {
+ Factory factory = ipojoHelper.getFactory("OneDuplicateInstance");
+ assertNotNull(factory);
+
+ // Create one instance
+ ComponentInstance instance = createInstanceOrFail(factory, "OneDuplicateInstance-0");
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(1, factory.getInstancesNames().size());
+ assertEquals(1, factory.getInstances().size());
+
+ assertContains("", factory.getInstancesNames().toArray(new String[1]), "OneDuplicateInstance-0");
+
+ // Create another instance with the same name
+ // The instance should not be created, and we should have only the first instance
+ try {
+ createInstance(factory, "OneDuplicateInstance-0");
+ fail("The instance OneDuplicateInstance-0 has been created with factory " + factory.getName() + ". "
+ + "It's shouldn't have been created has it's a duplicate instance");
+ } catch (UnacceptableConfiguration e) {
+ // expected Exception
+ } catch (Exception e){
+ fail("Cannot create instance OneDuplicateInstance-0 with factory " + factory.getName() + ". "
+ + "The wrong exception has been raised : " + e.toString());
+ }
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(1, factory.getInstancesNames().size());
+ assertEquals(1, factory.getInstances().size());
+
+ // Dispose of the instance
+ instance.dispose();
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(0, factory.getInstancesNames().size());
+ assertEquals(0, factory.getInstances().size());
+ }
+
+ @Test
+ public void testFiveInstances() {
+ Factory factory = ipojoHelper.getFactory("FiveInstances");
+ assertNotNull(factory);
+
+ // No instances for the moment
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(0, factory.getInstancesNames().size());
+ assertEquals(0, factory.getInstances().size());
+
+ // Create 5 instances
+ ComponentInstance[] instances = createNInstanceOrFail(factory, "FiveInstances", 5);
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(5, factory.getInstancesNames().size());
+ assertEquals(5, factory.getInstances().size());
+
+ assertContains("", factory.getInstancesNames().toArray(new String[5]), "FiveInstances-0");
+ assertContains("", factory.getInstancesNames().toArray(new String[5]), "FiveInstances-1");
+ assertContains("", factory.getInstancesNames().toArray(new String[5]), "FiveInstances-2");
+ assertContains("", factory.getInstancesNames().toArray(new String[5]), "FiveInstances-3");
+ assertContains("", factory.getInstancesNames().toArray(new String[5]), "FiveInstances-4");
+
+ // Dispose of instances 0, 3 and 2
+ // 2 instances left
+ instances[0].dispose();
+ instances[3].dispose();
+ instances[2].dispose();
+
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(2, factory.getInstancesNames().size());
+ assertEquals(2, factory.getInstances().size());
+
+ assertContains("", factory.getInstancesNames().toArray(new String[2]), "FiveInstances-1");
+ assertContains("", factory.getInstancesNames().toArray(new String[2]), "FiveInstances-4");
+
+ // Dispose of instances 1 and 4
+ // No instances left
+ instances[1].dispose();
+ instances[4].dispose();
+
+ assertNotNull(factory.getInstancesNames());
+ assertNotNull(factory.getInstances());
+
+ assertEquals(0, factory.getInstancesNames().size());
+ assertEquals(0, factory.getInstances().size());
+ }
+
+ public ComponentInstance[] createNInstanceOrFail(Factory factory, String baseName, Integer n) {
+ ComponentInstance[] instances = new ComponentInstance[n];
+ for (int i = 0; i < n; i++) {
+ instances[i] = createInstanceOrFail(factory, baseName + "-" + i);
+ }
+ return instances;
+ }
+
+ public ComponentInstance createInstanceOrFail(Factory factory, String name) {
+ ComponentInstance instance = null;
+ try {
+ instance = createInstance(factory, name);
+ } catch (Exception e) {
+ fail("Cannot create instance " + name + " with factory " + factory.getName() + ". "
+ + "Raised exception : " + e.toString());
+ }
+ return instance;
+ }
+
+ public ComponentInstance createInstance(Factory factory, String name)
+ throws MissingHandlerException, UnacceptableConfiguration, ConfigurationException {
+ Dictionary conf = new Hashtable();
+ conf.put("instance.name", name);
+ return factory.createComponentInstance(conf);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestObedience.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestObedience.java
new file mode 100644
index 0000000..97d5c8c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestObedience.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerManagerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * Check that instances are disposed when the factory is stopped.
+ */
+public class TestObedience extends Common {
+
+ @Test
+ public void testObedience() {
+ assertNull("Check no foo service", osgiHelper.getServiceReference(FooService.class.getName()));
+ ComponentFactory factory = (ComponentFactory) ipojoHelper.getFactory("Factories-FooProviderType-1");
+ assertNotNull("Check factory existing", factory);
+
+ Properties props1 = new Properties();
+ props1.put("instance.name", "foo1");
+ Properties props2 = new Properties();
+ props2.put("instance.name", "foo2");
+
+ ComponentInstance ci1 = null, ci2 = null;
+ try {
+ ci1 = factory.createComponentInstance(props1);
+ ci2 = factory.createComponentInstance(props2);
+ } catch (Exception e) {
+ fail("Cannot instantiate foo providers : " + e.getMessage());
+ }
+
+ assertTrue("Check foo1 validity", ci1.getState() == ComponentInstance.VALID);
+ assertTrue("Check foo2 validity", ci2.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check foo service", osgiHelper.getServiceReference(FooService.class.getName()));
+ assertEquals("Check the number of Foo", osgiHelper.getServiceReferences(FooService.class.getName(), null).length, 2);
+
+ factory.stop();
+
+ assertTrue("Check foo1 invalidity (" + ci1.getState() + ")", ci1.getState() == ComponentInstance.DISPOSED);
+ assertTrue("Check foo2 invalidity (" + ci1.getState() + ")", ci2.getState() == ComponentInstance.DISPOSED);
+
+ assertNull("Check no foo service", osgiHelper.getServiceReference(FooService.class.getName()));
+
+ factory.start();
+ assertNull("Check no foo service", osgiHelper.getServiceReference(FooService.class.getName()));
+ }
+
+ @Test
+ public void testDisposeAfterFactoryInvalidation() {
+ ComponentFactory cf = (ComponentFactory) ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.components.SimpleType");
+ assertNotNull("Check factory availability -1", cf);
+ assertEquals("Check factory state -1", Factory.VALID, cf.getState());
+
+ ServiceReference ref_arch = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "SimpleInstance");
+ assertNotNull("Check Architecture availability -1", ref_arch);
+
+ HandlerManagerFactory hf = (HandlerManagerFactory) ipojoHelper.getHandlerFactory("controller");
+ assertNotNull("Check handler availability -1", hf);
+ assertEquals("Check handler state -1", Factory.VALID, hf.getState());
+
+ // Stop the handler
+ hf.stop();
+ HandlerManagerFactory hf2 = (HandlerManagerFactory) ipojoHelper.getFactoryHelper().getHandlerFactory("controller", 1, false);
+ assertNull("Check handler availability -2", hf2);
+
+ // Check the factory invalidity
+ cf = (ComponentFactory) ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.components.SimpleType");
+ assertNotNull("Check factory availability -2", cf);
+ assertEquals("Check factory state -2", Factory.INVALID, cf.getState());
+
+ // Check the instance disappearance, the instance was disposed.
+ assertFalse("Check Architecture availability -1", ipojoHelper
+ .isServiceAvailableByName(Architecture.class.getName(), "SimpleInstance"));
+
+ // Restart the handler
+ hf.start();
+ hf2 = (HandlerManagerFactory) ipojoHelper.getHandlerFactory("controller");
+ assertNotNull("Check handler availability -3", hf2);
+
+ // Check the factory state
+ cf = (ComponentFactory) ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.components.SimpleType");
+ assertNotNull("Check factory availability -3", cf);
+ assertEquals("Check factory state -3", Factory.VALID, cf.getState());
+
+
+ // Check the instance re-creation
+ ref_arch = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "SimpleInstance");
+ assertNotNull("Check Architecture availability -3", ref_arch);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestReconfiguration.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestReconfiguration.java
new file mode 100644
index 0000000..fd54099
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestReconfiguration.java
@@ -0,0 +1,287 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestReconfiguration extends Common {
+
+ @Test
+ public void testRevalidationOnReconfiguration() {
+ ComponentFactory factory = (ComponentFactory) ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType");
+
+ // First inject a configuration triggering an exception of the validate method.
+ Properties props = new Properties();
+ props.put("prop", "KO");
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (UnacceptableConfiguration e) {
+ fail(e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail(e.getMessage());
+ } catch (ConfigurationException e) {
+ fail(e.getMessage());
+ }
+
+ assertNotNull(ci);
+ assertEquals("instance invalid", ComponentInstance.STOPPED, ci.getState());
+
+ // Reconfigure
+ props = new Properties();
+ props.put("prop", "OK");
+
+ ci.reconfigure(props);
+
+ assertNotNull(ci);
+ assertEquals("instance valid", ComponentInstance.VALID, ci.getState());
+ }
+
+ @Test public void testRevalidationOnReconfigurationUsingConfigAdmin() throws InvalidSyntaxException {
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("org.apache.felix.ipojo.runtime.core.components" +
+ ".ReconfigurableSimpleType", "?");
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ Dictionary props = configuration.getProperties();
+ if (props == null) {
+ props = new Properties();
+ }
+ // First inject a configuration triggering an exception of the validate method.
+ props.put("prop", "KO");
+
+ try {
+ configuration.update(props);
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ String pid = configuration.getPid();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ // Due to change in Architecture, the architecture service is still exposed but the instance state is STOPPED.
+ // This was made to ease debugging to dead instances.
+ Assert.assertTrue(ipojoHelper.isInstanceStopped(pid));
+
+ // Reconfigure
+ props = new Properties();
+ props.put("prop", "OK");
+
+ try {
+ configuration.update(props);
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ pid = configuration.getPid();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ Assert.assertNotNull("architecture", osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+ Architecture arch = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Is valid ?", ComponentInstance.VALID, arch.getInstanceDescription().getState());
+ }
+
+ @Test public void testRevalidationOnReconfigurationWithController() {
+ ComponentFactory factory = (ComponentFactory) ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType2");
+
+ // First inject a configuration triggering an exception of the validate method.
+ Properties props = new Properties();
+ props.put("prop", "KO");
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (UnacceptableConfiguration e) {
+ fail(e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail(e.getMessage());
+ } catch (ConfigurationException e) {
+ fail(e.getMessage());
+ }
+
+ assertNotNull(ci);
+ assertEquals("instance invalid", ComponentInstance.INVALID, ci.getState()); // Controller effect.
+
+ // Reconfigure
+ props = new Properties();
+ props.put("prop", "OK");
+
+ ci.reconfigure(props);
+
+ assertNotNull(ci);
+ assertEquals("instance valid", ComponentInstance.VALID, ci.getState());
+ }
+
+ @Test public void testRevalidationOnReconfigurationUsingConfigAdminAndController() throws InvalidSyntaxException {
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType2",
+ "?");
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ Dictionary props = configuration.getProperties();
+ if (props == null) {
+ props = new Properties();
+ }
+ // First inject a configuration triggering an exception of the validate method.
+ props.put("prop", "KO");
+
+ try {
+ configuration.update(props);
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ String pid = configuration.getPid();
+
+ // Wait for the processing of the first configuration.
+ grace();
+
+ // Invalid ... controller effect
+ Assert.assertNotNull("architecture", osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+ Architecture arch = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Is invalid ?", ComponentInstance.INVALID, arch.getInstanceDescription().getState());
+
+ // Reconfigure
+ props = new Properties();
+ props.put("prop", "OK");
+
+ try {
+ configuration.update(props);
+ grace();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ pid = configuration.getPid();
+
+
+ Assert.assertNotNull("architecture", osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+ arch = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Is valid ?", ComponentInstance.VALID, arch.getInstanceDescription().getState());
+ }
+
+ @Test public void testRevalidationOnReconfigurationOfTheController() {
+ ComponentFactory factory = (ComponentFactory) ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType3");
+
+ // First inject a configuration triggering an exception of the validate method.
+ Properties props = new Properties();
+ props.put("controller", "false");
+ ComponentInstance ci = null;
+ try {
+ ci = factory.createComponentInstance(props);
+ } catch (UnacceptableConfiguration e) {
+ fail(e.getMessage());
+ } catch (MissingHandlerException e) {
+ fail(e.getMessage());
+ } catch (ConfigurationException e) {
+ fail(e.getMessage());
+ }
+
+ assertNotNull(ci);
+ assertEquals("instance invalid", ComponentInstance.INVALID, ci.getState()); // Controller effect.
+
+ // Reconfigure
+ props = new Properties();
+ props.put("controller", "true");
+
+ ci.reconfigure(props);
+
+ assertNotNull(ci);
+ assertEquals("instance valid", ComponentInstance.VALID, ci.getState());
+ }
+
+ @Test public void testRevalidationOnReconfigurationUsingConfigAdminOfTheController() throws InvalidSyntaxException {
+ Configuration configuration = null;
+ try {
+ configuration = admin.createFactoryConfiguration("org.apache.felix.ipojo.runtime.core.components.ReconfigurableSimpleType3",
+ "?");
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ Dictionary props = configuration.getProperties();
+ if (props == null) {
+ props = new Properties();
+ }
+ // First inject a configuration triggering an exception of the validate method.
+ props.put("controller", "false");
+
+ try {
+ configuration.update(props);
+ grace();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ String pid = configuration.getPid();
+
+ // Invalid ... controller effect
+ Assert.assertNotNull("architecture", osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+ Architecture arch = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Is invalid ?", ComponentInstance.INVALID, arch.getInstanceDescription().getState());
+
+ // Reconfigure
+ props = new Properties();
+ props.put("controller", "true");
+
+ try {
+ configuration.update(props);
+ grace();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ pid = configuration.getPid();
+
+ Assert.assertNotNull("architecture", osgiHelper.getServiceReference(Architecture.class.getName(), "(architecture.instance=" + pid + ")"));
+ arch = (Architecture) osgiHelper.getServiceObject( Architecture.class.getName(), "(architecture.instance=" + pid + ")");
+
+ assertEquals("Is valid ?", ComponentInstance.VALID, arch.getInstanceDescription().getState());
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUnacceptableConfiguration.java b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUnacceptableConfiguration.java
new file mode 100644
index 0000000..8cd36c0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestUnacceptableConfiguration.java
@@ -0,0 +1,836 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Test unacceptable configuration.
+ */
+public class TestUnacceptableConfiguration extends Common {
+
+ /**
+ * Configuration without the name property.
+ */
+ @Test
+ public void testWithoutName() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ Properties p = new Properties();
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("an acceptable configuration is refused : " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Configuration without the name property.
+ */
+ @Test
+ public void testWithoutNameOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2opt");
+
+ Properties p = new Properties();
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("an acceptable configuration is refused : " + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Empty configuration.
+ */
+ @Test
+ public void testEmptyConfiguration() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+ Properties p = new Properties();
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Empty configuration.
+ */
+ @Test
+ public void testEmptyConfigurationOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2opt");
+ Properties p = new Properties();
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Empty configuration (just the name).
+ */
+ @Test
+ public void testEmptyConfiguration2() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+ Properties p = new Properties();
+ p.put("instance.name", "ko");
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ return;
+ }
+
+ fail("An unacceptable configuration is accepted");
+ }
+
+ /**
+ * Empty configuration (just the name).
+ */
+ @Test
+ public void testEmptyConfiguration2opt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+ Properties p = new Properties();
+ p.put("instance.name", "ko");
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+
+ }
+
+ /**
+ * Null configuration (accept).
+ */
+ @Test
+ public void testNull() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(null);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Null configuration (accept).
+ */
+ @Test
+ public void testNullOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2opt");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(null);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Null configuration (fail).
+ */
+ @Test
+ public void testNull2() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(null);
+ ci.dispose();
+ } catch (Exception e) {
+ return;
+ }
+
+ fail("An unacceptable configuration is accepted");
+ }
+
+ /**
+ * Null configuration (success).
+ */
+ @Test
+ public void testNull2Opt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(null);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+
+
+ }
+
+ /**
+ * Check static properties.
+ */
+ @Test
+ public void testStaticOK() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("long", 42l);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check static properties.
+ */
+ @Test
+ public void testStaticOKopt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("long", 42l);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check dynamic properties.
+ */
+ @Test
+ public void testDynamicOK() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Check dynamic properties.
+ */
+ @Test
+ public void testDynamicOKopt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dynopt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+
+ p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("An acceptable configuration is rejected (2) : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check inconsistent types.
+ */
+ @Test
+ public void testDynamicBadType() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check inconsistent types.
+ */
+ @Test
+ public void testDynamicBadTypeOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dynopt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("long", (long) 42);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+
+ p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected (2) : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration (with overriding).
+ */
+ @Test
+ public void testDynamicComplete() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration (with overriding).
+ */
+ @Test
+ public void testDynamicCompleteOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+
+
+ p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected (2) : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration.
+ */
+ @Test
+ public void testDynamicJustEnough() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration.
+ */
+ @Test
+ public void testDynamicJustEnoughOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+
+ p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("strAProp", new String[]{"a"});
+
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration.
+ */
+ @Test
+ public void testDynamicMix() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration.
+ */
+ @Test
+ public void testDynamicMixOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+
+ p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check uncomplete configuration.
+ */
+ @Test
+ public void testDynamicUncomplete() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ return;
+ }
+
+ fail("An unacceptable configuration is accepted");
+ }
+
+ /**
+ * Check uncomplete configuration.
+ */
+ @Test
+ public void testDynamicUncompleteOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+
+
+ }
+
+ /**
+ * Check good configuration (more properties).
+ */
+ @Test
+ public void testDynamicMore() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+ p.put("tralala", "foo");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check good configuration (more properties).
+ */
+ @Test
+ public void testDynamicMoreOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+ p.put("tralala", "foo");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check properties affecting services and component.
+ */
+ @Test
+ public void testDoubleProps() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+ p.put("boolean", false);
+ p.put("string", "toto");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check properties affecting services and component.
+ */
+ @Test
+ public void testDoublePropsOpt() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-Dyn2opt");
+
+ Properties p = new Properties();
+ p.put("instance.name", "ok");
+ p.put("int", 3);
+ p.put("boolean", true);
+ p.put("string", "absdir");
+ p.put("strAProp", new String[]{"a"});
+ p.put("intAProp", new int[]{1, 2});
+ p.put("boolean", false);
+ p.put("string", "toto");
+
+ ComponentInstance ci;
+ try {
+ ci = f.createComponentInstance(p);
+ ci.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is rejected : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Check instance name unicity.
+ */
+ @Test
+ public void testUnicity1() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ ComponentInstance ci1, ci2, ci3;
+ try {
+ ci1 = f.createComponentInstance(null);
+ ci2 = f.createComponentInstance(null);
+ ci3 = f.createComponentInstance(null);
+ assertThat("Check name ci1, ci2", ci1.getInstanceName(), not(ci2.getInstanceName()));
+ assertThat("Check name ci1, ci3", ci1.getInstanceName(), not(ci3.getInstanceName()));
+ assertThat("Check name ci3, ci2", ci3.getInstanceName(), not(ci2.getInstanceName()));
+ ci1.dispose();
+ ci2.dispose();
+ ci3.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Check instance name unicity.
+ */
+ @Test
+ public void testUnicity2() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ ComponentInstance ci1, ci2, ci3;
+ try {
+ Properties p1 = new Properties();
+ p1.put("instance.name", "name1");
+ ci1 = f.createComponentInstance(p1);
+ Properties p2 = new Properties();
+ p2.put("instance.name", "name2");
+ ci2 = f.createComponentInstance(p2);
+ Properties p3 = new Properties();
+ p3.put("instance.name", "name3");
+ ci3 = f.createComponentInstance(p3);
+ assertThat("Check name ci1, ci2", ci1.getInstanceName(), not(ci2.getInstanceName()));
+ assertThat("Check name ci1, ci3", ci1.getInstanceName(), not(ci3.getInstanceName()));
+ assertThat("Check name ci3, ci2", ci3.getInstanceName(), not(ci2.getInstanceName()));
+ ci1.dispose();
+ ci2.dispose();
+ ci3.dispose();
+ } catch (Exception e) {
+ fail("An acceptable configuration is refused");
+ }
+ }
+
+ /**
+ * Check instance name unicity.
+ */
+ @Test
+ public void testUnicity3() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+
+ ComponentInstance ci1 = null, ci2;
+ try {
+ Properties p1 = new Properties();
+ p1.put("instance.name", "name1");
+ ci1 = f.createComponentInstance(p1);
+ Properties p2 = new Properties();
+ p2.put("instance.name", "name1");
+ ci2 = f.createComponentInstance(p2);
+ assertThat("Check name ci1, ci2", ci1.getInstanceName(), not(ci2.getInstanceName()));
+ ci1.dispose();
+ ci2.dispose();
+ } catch (Exception e) {
+ if (ci1 != null) {
+ ci1.dispose();
+ }
+ // OK.
+ return;
+ }
+
+ fail("An unacceptable configuration is acceptable");
+ }
+
+ /**
+ * Check instance name unicity.
+ */
+ @Test
+ public void testUnicity4() {
+ Factory f = ipojoHelper.getFactory("Factories-FooProviderType-2");
+ Factory f2 = ipojoHelper.getFactory("Factories-FooProviderType-1");
+
+ ComponentInstance ci1 = null, ci2;
+ try {
+ Properties p1 = new Properties();
+ p1.put("instance.name", "name1");
+ ci1 = f.createComponentInstance(p1);
+ Properties p2 = new Properties();
+ p2.put("instance.name", "name1");
+ ci2 = f2.createComponentInstance(p2);
+ assertThat("Check name ci1, ci2", ci1.getInstanceName(), not(ci2.getInstanceName()));
+ ci1.dispose();
+ ci2.dispose();
+ } catch (Exception e) {
+ if (ci1 != null) {
+ ci1.dispose();
+ }
+ return;
+ }
+
+ fail("An unacceptable configuration is acceptable");
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/resources/exam.properties b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/resources/exam.properties
new file mode 100644
index 0000000..d8a500d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-test/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/pom.xml
new file mode 100644
index 0000000..43805cf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/pom.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-factory-version-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyComponent.java
new file mode 100644
index 0000000..0631bb6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyComponent.java
@@ -0,0 +1,30 @@
+/*
+ * 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.core.tests.components;
+
+import org.apache.felix.ipojo.core.tests.services.MyService;
+
+public class MyComponent implements MyService {
+
+ public void foo() {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyCons.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyCons.java
new file mode 100644
index 0000000..b502641
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/components/MyCons.java
@@ -0,0 +1,32 @@
+/*
+ * 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.core.tests.components;
+
+import org.apache.felix.ipojo.core.tests.services.MyService;
+
+public class MyCons {
+
+ private MyService[] services;
+
+ public MyCons() {
+ System.out.println("Bound to " + services.length);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/services/MyService.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/services/MyService.java
new file mode 100644
index 0000000..12ccb6f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/java/org/apache/felix/ipojo/core/tests/services/MyService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.core.tests.services;
+
+public interface MyService {
+
+ public void foo();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/cons.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/cons.xml
new file mode 100644
index 0000000..9f35629
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/cons.xml
@@ -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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component name="cons" classname="org.apache.felix.ipojo.core.tests.components.MyCons">
+ <requires field="services"/>
+ </component>
+ <instance component="cons" name="mycons"/>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/instances.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/instances.xml
new file mode 100644
index 0000000..2c41b1f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/instances.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <instance component="org.apache.felix.ipojo.core.tests.components.MyComponent"
+ version="1.0"
+ name="instance-v1"
+ />
+
+ <instance component="org.apache.felix.ipojo.core.tests.components.MyComponent"
+ version="1.1"
+ name="instance-v1.1"
+ />
+
+ <instance component="org.apache.felix.ipojo.core.tests.components.MyComponent"
+ name="instance-any"
+ />
+
+ <instance component="MyComponent"
+ name="MyComponentInstance"
+ />
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.1.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.1.xml
new file mode 100644
index 0000000..8d481d7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.1.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component classname="org.apache.felix.ipojo.core.tests.components.MyComponent" version="1.1">
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.xml
new file mode 100644
index 0000000..51c85fe
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/provider-v1.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component classname="org.apache.felix.ipojo.core.tests.components.MyComponent" version="1.0">
+ <provides/>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.core.tests.components.MyComponent" name="MyComponent">
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v1.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v1.xml
new file mode 100644
index 0000000..5b48b57
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v1.xml
@@ -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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component name="provider" classname="org.apache.felix.ipojo.core.tests.components.MyComponent" version="1.0">
+ <provides/>
+ </component>
+ <instance component="provider" version="1.0"/>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v2.xml b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v2.xml
new file mode 100644
index 0000000..40c9e88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/main/resources/vprovider-v2.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component name="provider" classname="org.apache.felix.ipojo.core.tests.components.MyComponent" version="2.0">
+ <provides/>
+ </component>
+ <instance component="provider" version="2.0"/>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/Common.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/Common.java
new file mode 100644
index 0000000..e959ee9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/Common.java
@@ -0,0 +1,91 @@
+/*
+ * 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.tests.core;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.core.tests.services.MyService;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+
+ public Option createServiceBundleV1() throws MalformedURLException {
+ File out = new File("target/tested/service-v1.jar");
+
+ if (out.exists()) {
+ return bundle(out.toURI().toURL().toExternalForm());
+ }
+
+ InputStream is = TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services")
+ .build(withBnd());
+ try {
+ FileUtils.copyInputStreamToFile(is, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the bundle");
+ }
+ }
+
+ public Option createServiceBundleV2() throws MalformedURLException {
+ File out = new File("target/tested/service-v2.jar");
+
+ if (out.exists()) {
+ return bundle(out.toURI().toURL().toExternalForm());
+ }
+
+ InputStream is = TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"2.0.0\"")
+ .build(withBnd());
+ try {
+ FileUtils.copyInputStreamToFile(is, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the bundle");
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
new file mode 100644
index 0000000..b11077e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.tests.core;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.core.tests.components.MyComponent;
+import org.apache.felix.ipojo.core.tests.services.MyService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+
+public class FactoryVersionTest extends Common {
+
+
+ @org.ops4j.pax.exam.Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ File provider1 = new File("target/tested/provider-v1.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderV1")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/provider-v1.xml"))),
+ provider1);
+
+ File provider2 = new File("target/tested/provider-v1.1.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderV1.1")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/provider-v1.1.xml"))),
+ provider2);
+
+ File instance = new File("target/tested/instance.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .set(Constants.BUNDLE_SYMBOLICNAME, "Instances")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/instances.xml"))),
+ instance);
+
+ List<Option> optionList = new ArrayList<Option>();
+ optionList.addAll(Arrays.asList(options));
+
+ optionList.add(createServiceBundleV1());
+ optionList.add(bundle(provider1.toURI().toURL().toExternalForm()));
+ optionList.add(bundle(provider2.toURI().toURL().toExternalForm()));
+ optionList.add(bundle(instance.toURI().toURL().toExternalForm()));
+
+ return optionList.toArray(new Option[optionList.size()]);
+ }
+
+ @Test
+ public void testDeploy() {
+ Bundle[] bundles = bc.getBundles();
+ for (Bundle bundle : bundles) {
+ System.out.println("Bundle deployed : " + bundle.getSymbolicName() + " / " + bundle.getState());
+ Assert.assertEquals(bundle.getSymbolicName() + " is not active", Bundle.ACTIVE, bundle.getState());
+ }
+ }
+
+ @Test
+ public void testInstanceArchitecture() {
+ // Version 1.0
+ ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "instance-v1");
+ Assert.assertNotNull(refv1);
+ Architecture archv1 = (Architecture) osgiHelper.getRawServiceObject(refv1);
+
+ String version = archv1.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertEquals("1.0", version);
+
+ // Version 1.1
+ ServiceReference refv11 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "instance-v1.1");
+ Assert.assertNotNull(refv11);
+ Architecture archv11 = (Architecture) osgiHelper.getRawServiceObject(refv11);
+
+ String version11 = archv11.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertEquals("1.1", version11);
+
+ // No Version
+ ServiceReference refany = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "instance-any");
+ Assert.assertNotNull(refany);
+ Architecture archany = (Architecture) osgiHelper.getRawServiceObject(refany);
+
+ String any = archany.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertNotNull(any);
+
+ // No version set in the factory, so no version.
+ ServiceReference refmci = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "MyComponentInstance");
+ Assert.assertNotNull(refmci);
+ Architecture archmcy = (Architecture) osgiHelper.getRawServiceObject(refmci);
+
+ String mci = archmcy.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertNull(mci);
+
+ }
+
+ @Test
+ public void testServiceProperty() throws InvalidSyntaxException {
+
+ // Version 1.0
+ //ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(MyService.class.getName(), "instance-v1");
+ ServiceReference[] refv1 = bc.getAllServiceReferences(MyService.class.getName(),
+ "(instance.name=instance-v1)");
+ Assert.assertNotNull(refv1);
+ String version = (String) refv1[0].getProperty("factory.version");
+ Assert.assertEquals("1.0", version);
+
+ // Version 1.1
+ for(ServiceReference ref : bc.getAllServiceReferences(null, null)) {
+ System.out.println("Service : " + ref.getProperty("instance.name"));
+ }
+
+ ServiceReference[] refv11 = bc.getAllServiceReferences(MyService.class.getName(),
+ "(instance.name=instance-v1.1)");
+ //ServiceReference refv11 = ipojoHelper.getServiceReferenceByName(MyService.class.getName(), "instance-v1.1");
+ Assert.assertNotNull(refv11);
+ String version11 = (String) refv11[0].getProperty("factory.version");
+
+ Assert.assertEquals("1.1", version11);
+
+ // No Version
+ ServiceReference[] refany = bc.getAllServiceReferences(MyService.class.getName(),
+ "(instance.name=instance-any)");
+
+ // ServiceReference refany = ipojoHelper.getServiceReferenceByName(MyService.class.getName(), "instance-any");
+ Assert.assertNotNull(refany);
+ String any = (String) refany[0].getProperty("factory.version");
+ Assert.assertNotNull(any);
+
+ // No version set in the factory, so no version.
+ ServiceReference[] refmci = bc.getAllServiceReferences(MyService.class.getName(),
+ "(instance.name=MyComponentInstance)");
+ //ServiceReference refmci = ipojoHelper.getServiceReferenceByName(MyService.class.getName(), "MyComponentInstance");
+ Assert.assertNotNull(refmci);
+ String mci = (String) refmci[0].getProperty("factory.version");
+ Assert.assertNull(mci);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java
new file mode 100644
index 0000000..9f2fb91
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-factory-version-test/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java
@@ -0,0 +1,279 @@
+/*
+ * 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.tests.core;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.core.tests.components.MyComponent;
+import org.apache.felix.ipojo.core.tests.components.MyCons;
+import org.apache.felix.ipojo.core.tests.services.MyService;
+import org.apache.felix.ipojo.handlers.dependency.Dependency;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.*;
+import org.ow2.chameleon.testing.helpers.Stability;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+@ExamReactorStrategy(PerMethod.class)
+public class VersionConflictTest extends Common {
+
+ @Inject
+ private BundleContext context;
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ List<Option> options = new ArrayList<Option>();
+ options.addAll(Arrays.asList(super.config()));
+
+ File tmp = new File("target/tmp");
+ tmp.mkdirs();
+
+ File f1 = new File(tmp, "service-interface-v1.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterfaceV1")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"1.0.0\"")
+ .build(withBnd()),
+ f1);
+
+ File f2 = new File(tmp, "service-interface-v2.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterfaceV2")
+ .set(Constants.BUNDLE_VERSION, "2.0.0")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"2.0.0\"")
+ .build(withBnd()),
+ f2);
+
+ File c1 = new File(tmp, "component-v1.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderV1")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"1.0.0\"")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/vprovider-v1.xml"))),
+ c1);
+
+ File c2 = new File(tmp, "component-v2.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ProviderV2")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"2.0.0\"")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/vprovider-v2.xml"))),
+ c2);
+
+ File cons = new File(tmp, "cons.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyCons.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyCons")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"2.0.0\"")
+ .set(Constants.BUNDLE_VERSION, "2.0")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/cons.xml"))),
+ cons);
+
+ File consV1 = new File(tmp, "cons-v1.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyCons.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyCons")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.core.tests.services; version=\"[1.0.0, " +
+ "1.1.0)\"")
+ .set(Constants.BUNDLE_VERSION, "1.0")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/cons.xml"))),
+ consV1);
+
+ Option[] opt = options(
+ systemProperty("url1").value(f1.toURI().toURL().toExternalForm()),
+ systemProperty("url2").value(f2.toURI().toURL().toExternalForm()),
+
+ systemProperty("c1").value(c1.toURI().toURL().toExternalForm()),
+ systemProperty("c2").value(c2.toURI().toURL().toExternalForm()),
+ systemProperty("cons").value(cons.toURI().toURL().toExternalForm()),
+ systemProperty("consV1").value(consV1.toURI().toURL().toExternalForm())
+ );
+
+ options.addAll(Arrays.asList(opt));
+
+ return options.toArray(new Option[options.size()]);
+ }
+
+// @ProbeBuilder
+// public TestProbeBuilder probe(TestProbeBuilder builder) {
+// builder.setHeader(Constants.IMPORT_PACKAGE, "org.osgi.framework, org.apache.felix.ipojo, " +
+// "org.ow2.chameleon.testing.helpers, org.osgi.service.packageadmin, " +
+// "org.apache.felix.ipojo.architecture, org.apache.felix.ipojo.handlers.dependency");
+// builder.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "org.ops4j.pax.exam,org.junit,javax.inject," +
+// "org.ops4j.pax.exam.options");
+// builder.setHeader("Bundle-ManifestVersion", "2");
+// return builder;
+// }
+
+ public boolean isKF() {
+ return bc.getClass().toString().contains("knopflerfish");
+ }
+
+ @Test
+ public void deployBundlesAtRuntime() throws MalformedURLException, BundleException, InvalidSyntaxException {
+ if (isKF()) {
+ System.out.println("Test disabled on knopflerfish");
+ return;
+ }
+
+ Bundle b1 = context.installBundle(context.getProperty("url1"));
+ b1.start();
+
+
+ Bundle b3 = context.installBundle(context.getProperty("c1"));
+ b3.start();
+
+ Bundle b2 = context.installBundle(context.getProperty("url2"));
+ b2.start();
+
+ Bundle b4 = context.installBundle(context.getProperty("c2"));
+ b4.start();
+
+ Bundle b5 = context.installBundle(context.getProperty("cons"));
+ b5.start();
+
+ Stability.waitForStability(bc);
+
+ Bundle[] bundles = context.getBundles();
+ for (Bundle bundle : bundles) {
+ System.out.println("bundle " + bundle.getSymbolicName() + " : " + (bundle.getState() == Bundle.ACTIVE));
+ //Assert.assertEquals(bundles[i].getSymbolicName() + " is not active", Bundle.ACTIVE, bundles[i].getState());
+ }
+
+// Bundle consBundle = osgiHelper.getBundle("MyCons");
+// BundleWiring wiring = consBundle.adapt(BundleWiring.class);
+// System.out.println("Bundle Wiring req: ");
+// for (BundleWire wire : wiring.getRequiredWires(null)) {
+// System.out.println(wire.getCapability().getAttributes() + " - " + wire.getCapability().getDirectives());
+// }
+
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=mycons)", 2000);
+
+ // Check that the two services are provided.
+ ServiceReference[] refs = context.getAllServiceReferences("org.apache.felix.ipojo.core.tests.services.MyService", null);
+ Assert.assertNotNull(refs);
+ Assert.assertEquals(2, refs.length);
+
+ ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "mycons");
+ Assert.assertNotNull(refv1);
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(refv1);
+
+ HandlerDescription desc = arch.getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:requires");
+ Assert.assertNotNull(desc);
+
+ DependencyHandlerDescription d = (DependencyHandlerDescription) desc;
+ Assert.assertNotNull(d.getDependencies());
+ Assert.assertEquals(1, d.getDependencies().length);
+
+ DependencyDescription dep = d.getDependencies()[0];
+ Assert.assertEquals(Dependency.RESOLVED, dep.getState());
+
+ Assert.assertEquals(1, dep.getServiceReferences().size());
+ ServiceReference r = dep.getServiceReferences().get(0);
+ Assert.assertEquals("provider", r.getProperty("factory.name"));
+ Assert.assertEquals("2.0", r.getProperty("factory.version"));
+ }
+
+ @Test
+ @Ignore("Does not work anymore, but the scenario runs as expected in a regular framework. The check find the " +
+ "version 2.0 of the service instead of the 1.0")
+ public void deployBundlesAtRuntimeV1() throws MalformedURLException, BundleException, InvalidSyntaxException {
+
+ Bundle b1 = context.installBundle(context.getProperty("url1"));
+ b1.start();
+
+
+ Bundle b3 = context.installBundle(context.getProperty("c1"));
+ b3.start();
+
+ Bundle b2 = context.installBundle(context.getProperty("url2"));
+ b2.start();
+
+ Bundle b4 = context.installBundle(context.getProperty("c2"));
+ b4.start();
+
+ Bundle b5 = context.installBundle(context.getProperty("consV1"));
+ b5.start();
+
+
+ Bundle[] bundles = context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ System.out.println("bundle " + bundles[i].getSymbolicName() + " : " + (bundles[i].getState() == Bundle.ACTIVE));
+ }
+
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=mycons)", 2000);
+
+ // Check that the two services are provided.
+ ServiceReference[] refs = context.getAllServiceReferences("org.apache.felix.ipojo.core.tests.services.MyService", null);
+ Assert.assertNotNull(refs);
+ Assert.assertEquals(2, refs.length);
+
+ ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "mycons");
+ Assert.assertNotNull(refv1);
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(refv1);
+
+ HandlerDescription desc = arch.getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:requires");
+ Assert.assertNotNull(desc);
+
+ DependencyHandlerDescription d = (DependencyHandlerDescription) desc;
+ Assert.assertNotNull(d.getDependencies());
+ Assert.assertEquals(1, d.getDependencies().length);
+
+ DependencyDescription dep = d.getDependencies()[0];
+ Assert.assertEquals(Dependency.RESOLVED, dep.getState());
+
+ Assert.assertEquals(1, dep.getServiceReferences().size());
+ ServiceReference r = dep.getServiceReferences().get(0);
+
+ Assert.assertEquals("provider", r.getProperty("factory.name"));
+ Assert.assertEquals("1.0", r.getProperty("factory.version"));
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-handler-test/pom.xml
new file mode 100644
index 0000000..a952b5c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-handler-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/DummyImpl.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/DummyImpl.java
new file mode 100644
index 0000000..08f9056
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/DummyImpl.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.Dummy;
+
+
+/**
+ * Just a Dummy test
+ */
+public class DummyImpl implements Dummy {
+
+ private void start() {
+ }
+
+ private void stop() {
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
new file mode 100644
index 0000000..b45d54e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+
+public class MyComponent implements MyService {
+
+ public void foo() {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/DummyHandler.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/DummyHandler.java
new file mode 100644
index 0000000..2414312
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/DummyHandler.java
@@ -0,0 +1,74 @@
+/*
+ * 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.handlers;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.runtime.core.services.User;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+
+
+public class DummyHandler extends PrimitiveHandler {
+
+ public DummyHandler() {
+ }
+
+ /*------------------------------------------------------------*
+ * Handler Specific Methods *
+ *------------------------------------------------------------*/
+
+ @Override
+ public void initializeComponentFactory(ComponentTypeDescription typeDesc, Element metadata) throws ConfigurationException {
+ // Initialize
+ super.initializeComponentFactory(typeDesc, metadata);
+ }
+
+ @Override
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ }
+
+
+ public void bindUser(User user) {
+ // in order to test
+ user.getName();
+ }
+
+ public void unBindUser(User user) {
+ // in order to test
+ user.getType();
+ }
+
+ public void validate() {
+ // do nothing
+ }
+
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void stop() {
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/EmptyHandler.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/EmptyHandler.java
new file mode 100644
index 0000000..22eef12
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/handlers/EmptyHandler.java
@@ -0,0 +1,46 @@
+/*
+ * 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.handlers;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.Dictionary;
+
+public class EmptyHandler extends PrimitiveHandler {
+
+ @Override
+ public void configure(Element arg0, Dictionary arg1)
+ throws ConfigurationException {
+ info("Configured");
+ }
+
+ @Override
+ public void start() {
+ info("Started");
+ }
+
+ @Override
+ public void stop() {
+ info("Stopped");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Dummy.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Dummy.java
new file mode 100644
index 0000000..08fcf47
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/Dummy.java
@@ -0,0 +1,24 @@
+/*
+ * 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.services;
+
+public interface Dummy {
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java
new file mode 100644
index 0000000..fc5e2ce
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface MyService {
+
+ public void foo();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/User.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/User.java
new file mode 100644
index 0000000..2d7ebbc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/User.java
@@ -0,0 +1,30 @@
+/*
+ * 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.services;
+
+/**
+ * Simple users.
+ */
+public interface User {
+
+ public String getName();
+
+ public int getType();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-component.xml b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-component.xml
new file mode 100644
index 0000000..8e0b326
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-component.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<iPOJO xmlns:dummy="org.apache.felix.ipojo.test.dummy.handler.dummyhandler">
+ <component className="org.apache.felix.ipojo.runtime.core.components.DummyImpl" name="dummy.test">
+ <callback transition="validate" method="start" />
+ <callback transition="invalidate" method="stop" />
+
+ <dummy:dummy/>
+ </component>
+</iPOJO>
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-handler.xml b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-handler.xml
new file mode 100644
index 0000000..3152b42
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/dummy-handler.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<!--
+ <iPOJO xmlns:wbp="org.apache.felix.ipojo.whiteboard"
+ xmlns:jmx="org.apache.felix.ipojo.handlers.jmx">
+-->
+<iPOJO>
+ <!-- Declare the handler -->
+ <handler classname="org.apache.felix.ipojo.runtime.core.handlers.DummyHandler" name="dummy"
+ namespace="org.apache.felix.ipojo.test.dummy.handler.dummyhandler" architecture="true">
+
+ <requires optional="true" aggregate="true">
+ <callback type="bind" method="bindUser"/>
+ <callback type="unbind" method="unBindUser"/>
+ </requires>
+ <callback transition="validate" method="validate"/>
+ </handler>
+</iPOJO>
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/ignorecase.xml b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/ignorecase.xml
new file mode 100644
index 0000000..5774c76
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/main/resources/ignorecase.xml
@@ -0,0 +1,39 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:ex="org.apache.felix.ipojo.tests.core.handler">
+
+<!-- Empty handler, name and namespace written strangely -->
+<handler
+ name="EmPtY"
+ namespace="orG.apAche.feliX.iPOJO.tests.CORE.hAnDlEr"
+ classname="org.apache.felix.ipojo.runtime.core.handlers.EmptyHandler">
+</handler>
+
+<component classname="org.apache.felix.ipojo.runtime.core.components.MyComponent" name="IgnoreCase-1">
+ <ex:empty/>
+</component>
+<instance component="IgnoreCase-1" name="IgnoreCase-1"/>
+
+<component classname="org.apache.felix.ipojo.runtime.core.components.MyComponent" name="IgnoreCase-2">
+ <ex:eMptY/>
+</component>
+<instance component="IgnoreCase-2" name="IgnoreCase-2"/>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..20da196
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+
+ @Override
+ public boolean deployMockito() {
+ return true;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/DummyHandlerTest.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/DummyHandlerTest.java
new file mode 100644
index 0000000..35920eb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/DummyHandlerTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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;
+
+import junit.framework.Assert;
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.runtime.core.components.DummyImpl;
+import org.apache.felix.ipojo.runtime.core.handlers.DummyHandler;
+import org.apache.felix.ipojo.runtime.core.services.Dummy;
+import org.apache.felix.ipojo.runtime.core.services.User;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+
+@ExamReactorStrategy(PerMethod.class)
+public class DummyHandlerTest extends Common {
+
+ private static final String DUMMY_TEST_FACTORY = "dummy.test";
+ /*
+ * Number of mock object by test.
+ */
+ private static final int NB_MOCK = 10;
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ // Build handler bundle
+ File handlerJar = new File("target/bundles/handler.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(DummyHandler.class)
+ .set(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, "Dummy.Handler")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/dummy-handler.xml"))),
+ handlerJar);
+
+ // Build consumer bundle
+ File dummyJar = new File("target/bundles/dummy.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(DummyImpl.class)
+ .set(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, "Dummy.Bundle")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/dummy-component.xml"))),
+ dummyJar);
+
+
+ return OptionUtils.combine(options,
+ streamBundle(TinyBundles.bundle()
+ .add(Dummy.class)
+ .add(User.class)
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .set(Constants.BUNDLE_SYMBOLICNAME, "service")
+ .build(withBnd())
+ ),
+ bundle(handlerJar.toURI().toURL().toExternalForm()),
+ bundle(dummyJar.toURI().toURL().toExternalForm())
+ );
+ }
+
+ /**
+ * Basic Test, in order to know if the instance is correctly create.
+ */
+ @Test
+ public void testDummyTestInstance() {
+ ComponentInstance instance;
+
+ // Get the factory
+ Factory factory = Tools.getValidFactory(osgiHelper, DUMMY_TEST_FACTORY);
+ Assert.assertNotNull(factory);
+
+ // Create an instance
+ try {
+ instance = factory.createComponentInstance(null);
+ } catch (UnacceptableConfiguration e) {
+ throw new AssertionError(e);
+ } catch (MissingHandlerException e) {
+ throw new AssertionError(e);
+ } catch (ConfigurationException e) {
+ throw new AssertionError(e);
+ }
+
+ // Must be valid now
+ Assert.assertEquals(instance.getState(), ComponentInstance.VALID);
+
+ // Stop the instance
+ instance.stop();
+ Assert.assertEquals(instance.getState(), ComponentInstance.STOPPED);
+
+ // Start the instance
+ instance.start();
+ Assert.assertEquals(instance.getState(), ComponentInstance.VALID);
+ }
+
+ /**
+ * Test if the bind and unbind methods are called when the bind service are registered after the instance creation
+ */
+ @Test
+ public void testDummyTestBindAfterStart() {
+ // Get the factory
+ Factory factory = Tools.getValidFactory(osgiHelper, DUMMY_TEST_FACTORY);
+ assertNotNull(factory);
+
+ // Create an instance, it will be disposed by the helper
+ ComponentInstance instance = ipojoHelper.createComponentInstance(DUMMY_TEST_FACTORY);
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+
+ Map<MyUser, ServiceRegistration> registrations = new HashMap<MyUser, ServiceRegistration>();
+
+ for (int i = 0; i < NB_MOCK; i++) {
+ MyUser service = new MyUser();
+ ServiceRegistration sr = bc.registerService(User.class.getName(), service, null);
+ registrations.put(service, sr);
+ }
+
+ TimeUtils.grace(200);
+ assertEquals(osgiHelper.getServiceReferences(User.class, null).length, NB_MOCK);
+
+ //verify that the bind method of the handler has been called
+ for (MyUser user : registrations.keySet()) {
+ assertTrue(user.name);
+ }
+
+ //verify that the unbind has been called
+ for (MyUser user : registrations.keySet()) {
+ registrations.get(user).unregister();
+ assertTrue(user.type);
+ }
+ }
+
+ /**
+ * Test if the bind and unbind methods when the bind services are registered before the instance creation
+ */
+ @Test
+ public void testDummyTestBindBeforeStart() {
+ ComponentInstance instance = null;
+
+ Map<MyUser, ServiceRegistration> registrations = new HashMap<MyUser, ServiceRegistration>();
+
+ for (int i = 0; i < NB_MOCK; i++) {
+ MyUser service = new MyUser();
+ ServiceRegistration sr = bc.registerService(User.class.getName(), service, null);
+ registrations.put(service, sr);
+ }
+
+ // Get the factory
+ Factory factory = Tools.getValidFactory(osgiHelper, DUMMY_TEST_FACTORY);
+ assertNotNull(factory);
+
+ // The instance will be disposed by the helper
+ ipojoHelper.createComponentInstance(DUMMY_TEST_FACTORY);
+
+ //verify that the bind method of the handler has been called
+ for (MyUser user : registrations.keySet()) {
+ assertTrue(user.name);
+ }
+
+ //verify that the unbind has been called
+ for (MyUser user : registrations.keySet()) {
+ registrations.get(user).unregister();
+ assertTrue(user.type);
+ }
+ }
+
+ private class MyUser implements User {
+
+ boolean name;
+ boolean type;
+
+ @Override
+ public String getName() {
+ name = true;
+ return "name";
+ }
+
+ @Override
+ public int getType() {
+ type = true;
+ return 1;
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/IgnoreCaseHandlerSelectionTest.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/IgnoreCaseHandlerSelectionTest.java
new file mode 100644
index 0000000..c7ae7bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/IgnoreCaseHandlerSelectionTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.handlers.EmptyHandler;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * Check that the handler selection ignore case.
+ * An empty handler declared with
+ * name="EmPtY" and namespace="orG.apAche.feliX.iPOJO.tests.CORE.hAnDlEr"
+ * is declared, and two instances using this handler are created. The test is
+ * successful is the two instances are created correctly.
+ * Test about Felix-1318 : Case mismatch problem of iPOJO custom handler name
+ */
+public class IgnoreCaseHandlerSelectionTest extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ File tmp = new File("target/bundles");
+ tmp.mkdirs();
+
+ // Build handler bundle
+ File serviceJar = new File("target/bundles/service.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd()),
+ serviceJar);
+
+ // Build component and handler bundle
+ File componentJar = new File("target/bundles/componentAndHandler.jar");
+ FileUtils.copyInputStreamToFile(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .add(EmptyHandler.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "IgnoreCase")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/ignorecase.xml"))),
+ componentJar);
+
+ return OptionUtils.combine(options,
+ bundle(serviceJar.toURI().toURL().toExternalForm()),
+ bundle(componentJar.toURI().toURL().toExternalForm()));
+ }
+
+ @Test
+ public void testDeploy() {
+ Bundle[] bundles = bc.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ Assert.assertEquals(bundles[i].getSymbolicName() + " is not active", Bundle.ACTIVE, bundles[i].getState());
+ }
+ }
+
+ /**
+ * Checks that the handler is declared and accessible.
+ */
+ @Test
+ public void testHandlerAvailability() {
+ ServiceReference[] refs = osgiHelper.getServiceReferences(HandlerFactory.class.getName(), null);
+ for (ServiceReference ref : refs) {
+ String name = (String) ref.getProperty("handler.name");
+ String ns = (String) ref.getProperty("handler.namespace");
+ if (name != null
+ && name.equalsIgnoreCase("EmPtY") // Check with ignore case.
+ && ns != null
+ && ns.equalsIgnoreCase("orG.apAche.feliX.iPOJO.tests.CORE.hAnDlEr")) { // Check with ignore case.
+ Integer state = (Integer) ref.getProperty("factory.state");
+ if (state != null) {
+ Assert.assertEquals(Factory.VALID, state.intValue());
+ return; // Handler found and valid.
+ } else {
+ Assert.fail("Handler found but no state exposed");
+ }
+ }
+ }
+ Assert.fail("Handler not found");
+ }
+
+ /**
+ * Check that the instance is correctly created with "empty".
+ */
+ @Test
+ public void testCreationOfIgnoreCase1() {
+ ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "IgnoreCase-1");
+ Assert.assertNotNull(refv1);
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(refv1);
+ Assert.assertEquals(ComponentInstance.VALID, arch.getInstanceDescription().getState());
+
+ HandlerDescription desc = arch.getInstanceDescription()
+ .getHandlerDescription("orG.apAche.feliX.iPOJO.tests.CORE.hAnDlEr:EmPtY"); // Check with the declared name.
+
+ Assert.assertNotNull(desc);
+ Assert.assertTrue(desc.isValid());
+ }
+
+ /**
+ * Check that the instance is correctly created with "eMptY".
+ */
+ @Test
+ public void testCreationOfIgnoreCase2() {
+ ServiceReference refv1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "IgnoreCase-2");
+ Assert.assertNotNull(refv1);
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(refv1);
+ Assert.assertEquals(ComponentInstance.VALID, arch.getInstanceDescription().getState());
+
+ HandlerDescription desc = arch.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo.tests.core.handler:empty"); // Check with different case.
+ Assert.assertNotNull(desc);
+ Assert.assertTrue(desc.isValid());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Tools.java b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Tools.java
new file mode 100644
index 0000000..0e73545
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-handler-test/src/test/java/org/apache/felix/ipojo/runtime/core/Tools.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+
+public class Tools {
+
+
+ /**
+ * Get the Factory linked to the given pid
+ *
+ * @param osgi the osgi test helper
+ * @param name the factory name
+ * @return The factory or {@literal null} if not found.
+ */
+ public static Factory getValidFactory(final OSGiHelper osgi, final String name) {
+ // Wait for service first.
+ ServiceReference ref = osgi.waitForService(
+ Factory.class.getName(),
+ "(&(factory.state=1)(factory.name=" + name + "))",
+ 1000, false);
+
+ if (ref != null) {
+ // Get the factory
+ return (Factory) osgi.getRawServiceObject(ref);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/pom.xml
new file mode 100644
index 0000000..fb578cc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-lifecycle-callback-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallbackWithErrorCheckService.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallbackWithErrorCheckService.java
new file mode 100644
index 0000000..7a24568
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CallbackWithErrorCheckService.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class CallbackWithErrorCheckService extends ParentClass implements CheckService {
+
+
+ public void start() {
+ throw new NullPointerException();
+ }
+
+ public void stop() {
+ }
+
+ public boolean check() {
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties p = new Properties();
+ return p;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..8b2d55e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java
new file mode 100644
index 0000000..3c69e69
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class LifecycleControllerTest implements CheckService {
+
+ private boolean m_state = true;
+ private String m_conf;
+
+ public void setConf(String newConf) {
+ if (newConf.equals("foo")) {
+ m_state = true;
+ } else {
+ m_state = false;
+ }
+ }
+
+ public boolean check() {
+ return m_state;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("conf", m_conf);
+ props.put("state", new Boolean(m_state));
+ return props;
+ }
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
new file mode 100644
index 0000000..33d385c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CallbackCheckService.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CallbackCheckService.java
new file mode 100644
index 0000000..4fbde64
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CallbackCheckService.java
@@ -0,0 +1,67 @@
+/*
+ * 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.services;
+
+import org.apache.felix.ipojo.runtime.core.components.ParentClass;
+
+import java.util.Properties;
+
+public class CallbackCheckService extends ParentClass implements CheckService {
+
+ int i = 0;
+
+ FooService fs;
+
+ public static CallbackCheckService singleton;
+
+ public static int count = 0;
+
+ private static CallbackCheckService singleton() {
+ if (singleton == null) {
+ count++;
+ singleton = new CallbackCheckService();
+ }
+ return singleton;
+ }
+
+ public static CallbackCheckService several() {
+ count++;
+ return new CallbackCheckService();
+ }
+
+ private void start() {
+ i++;
+ }
+
+ protected void stop() {
+ i++;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties p = new Properties();
+ p.put("int", new Integer(i));
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..ef3f6c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/main/resources/metadata.xml
@@ -0,0 +1,108 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ >
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="LFCB-FooProviderType-1" architecture="true">
+ <provides/>
+ </component>
+
+ <!-- Lifecycle Callback -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.services.CallbackCheckService"
+ name="LFCB-CallbackCheckService" architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.services.CallbackCheckService"
+ name="LFCB-ParentCallbackCheckService" architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ <callback transition="validate" method="parentStart"/>
+ <callback transition="invalidate" method="parentStop"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.services.CallbackCheckService"
+ immediate="true" name="LFCB-ImmediateCallbackCheckService"
+ architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.services.CallbackCheckService"
+ immediate="true" name="LFCB-ImmediateCallbackCheckServiceSingleton"
+ factory-method="singleton" architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.services.CallbackCheckService"
+ immediate="true" name="LFCB-ImmediateCallbackCheckServiceSeveral"
+ factory-method="several" architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+
+ <!-- Test initialization error -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.CallbackWithErrorCheckService"
+ name="LFCB-CallbackWithError">
+ <provides/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+
+ <!-- Component type initially defined in another project, moved here after pax exam 3 -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="Factories-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4" mandatory="true"/>
+ <property name="boolean" field="boolProp" mandatory="true"/>
+ <property name="string" field="strProp" mandatory="true"/>
+ <property name="strAProp" field="strAProp" mandatory="true"/>
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }" mandatory="true"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.LifecycleControllerTest"
+ name="LFC-Test-Immediate" immediate="true" architecture="true">
+ <provides />
+ <controller field="m_state" />
+ <properties>
+ <property name="conf" field="m_conf" method="setConf" />
+ </properties>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..0ba6a79
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ // No custom configuration required.
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallback.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallback.java
new file mode 100644
index 0000000..027500a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallback.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestCallback extends Common {
+
+ ComponentInstance instance; // Instance under test
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Properties p2 = new Properties();
+ p2.put("instance.name", "fooProvider");
+ fooProvider = ipojoHelper.createComponentInstance("LFCB-FooProviderType-1", p2);
+ fooProvider.stop();
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "callback");
+ instance = ipojoHelper.createComponentInstance("LFCB-CallbackCheckService", p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ fooProvider.dispose();
+ instance = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testCallback() {
+ // Check instance is invalid
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper
+ .getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+ assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);
+
+ // Start fooprovider
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check int property
+ Integer index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 1", index.intValue(), 1);
+
+ assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+
+ assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check int property
+ index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 2 (" + index.intValue() + ")", index.intValue(), 3);
+
+ assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorCallback.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorCallback.java
new file mode 100644
index 0000000..0ec7e4e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorCallback.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * Test the fix for FELIX-1965.
+ * When a validate callback throws an exception, the service is still provided.
+ */
+public class TestErrorCallback extends Common {
+
+ ComponentInstance instance; // Instance under test
+
+ @After
+ public void tearDown() {
+ if (instance != null) {
+ instance.dispose();
+ instance= null;
+ }
+ }
+
+ @Test
+ public void testErrorInValidateCallback() {
+ Properties p2 = new Properties();
+ p2.put("instance.name","error");
+ instance = ipojoHelper.createComponentInstance("LFCB-CallbackWithError", p2);
+
+ // The service should not be provided as the start method has thrown an exception
+ ServiceReference ref = osgiHelper.getServiceReference(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")");
+ assertNull(ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallback.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallback.java
new file mode 100644
index 0000000..0f86720
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallback.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestImmediateCallback extends Common {
+
+ ComponentInstance instance; // Instance under test
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Properties p2 = new Properties();
+ p2.put("instance.name", "fooProvider");
+ fooProvider = ipojoHelper.createComponentInstance("LFCB-FooProviderType-1", p2);
+ fooProvider.stop();
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "callback");
+ instance = ipojoHelper.createComponentInstance("LFCB-ImmediateCallbackCheckService", p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ fooProvider.dispose();
+ instance = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testCallback() {
+ // Check instance is invalid
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper
+ .getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+ assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);
+
+ // Start fooprovider
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);
+ // Check int property
+ Integer index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 1 (" + index + ")", index.intValue(), 1);
+
+ fooProvider.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+
+ assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check int property
+ index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 2 (" + index + ")", index.intValue(), 3);
+
+ assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSeveralFactories.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSeveralFactories.java
new file mode 100644
index 0000000..23796c4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSeveralFactories.java
@@ -0,0 +1,124 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.CallbackCheckService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestImmediateCallbackSeveralFactories extends Common {
+
+ ComponentInstance instance; // Instance under test
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Properties p2 = new Properties();
+ p2.put("instance.name", "fooProvider");
+ fooProvider = ipojoHelper.createComponentInstance("LFCB-FooProviderType-1", p2);
+ fooProvider.stop();
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "callback");
+ instance = ipojoHelper.createComponentInstance("LFCB-ImmediateCallbackCheckServiceSeveral", p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ fooProvider.dispose();
+ instance = null;
+ fooProvider = null;
+ CallbackCheckService.count = 0;
+ }
+
+ @Test
+ public void testCallback() {
+ // Check instance is invalid
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(),
+ instance.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper
+ .getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+ assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);
+
+ // Start fooprovider
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);
+ // Check int property
+ Integer index = (Integer) (cs.getProps().get("int"));
+ Integer count = (Integer) (cs.getProps().get("count"));
+ assertEquals("Check int property - 1 (" + index + ")", index.intValue(), 1);
+ assertEquals("Check count property - 1 (" + count + ")", count.intValue(), 1);
+
+ fooProvider.stop();
+
+ //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+
+ assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check int property
+ index = (Integer) (cs.getProps().get("int"));
+ count = (Integer) (cs.getProps().get("count"));
+ assertEquals("Check int property - 2 (" + index + ")", index.intValue(), 3);
+ assertEquals("Check count property - 2 (" + count + ")", count.intValue(), 1);
+
+ assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSingletonFactory.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSingletonFactory.java
new file mode 100644
index 0000000..1c4f9a0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateCallbackSingletonFactory.java
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.CallbackCheckService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestImmediateCallbackSingletonFactory extends Common {
+
+ ComponentInstance instance; // Instance under test
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Properties p2 = new Properties();
+ p2.put("instance.name", "fooProvider");
+ fooProvider = ipojoHelper.createComponentInstance("LFCB-FooProviderType-1", p2);
+ fooProvider.stop();
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "callback");
+ instance = ipojoHelper.createComponentInstance("LFCB-ImmediateCallbackCheckServiceSingleton", p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ fooProvider.dispose();
+ instance = null;
+ fooProvider = null;
+ CallbackCheckService.count = 0;
+ CallbackCheckService.singleton = null;
+ }
+
+ @Test
+ public void testCallback() {
+ // Check instance is invalid
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper
+ .getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+ assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);
+
+ // Start fooprovider
+ fooProvider.start();
+
+ // Check instance validity
+ // id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);
+ // Check int property
+ Integer index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 1 (" + index + ")", index.intValue(), 1);
+
+ fooProvider.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+
+ assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.start();
+
+ // Check instance validity
+ // id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check int property
+ index = (Integer) (cs.getProps().get("int"));
+ assertEquals("Check int property - 2 (" + index + ")", index.intValue(), 3);
+
+ assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java
new file mode 100644
index 0000000..22743e0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestImmediateLifeCycleController extends Common {
+
+ private ComponentInstance under;
+ private Factory factory;
+
+ @Before
+ public void setUp() {
+ factory = ipojoHelper.getFactory("LFC-Test-Immediate");
+ }
+
+ @Test
+ public void testOne() {
+ Properties props = new Properties();
+ props.put("conf", "foo");
+ props.put("instance.name", "under");
+ under = ipojoHelper.createComponentInstance("LFC-Test-Immediate", props);
+
+ // The conf is correct, the PS must be provided
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under");
+ assertNotNull("Check service availability -1", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 1", cs.check());
+ bc.ungetService(ref);
+
+ // Reconfigure the instance with a bad configuration
+ props.put("conf", "bar"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under"));
+
+ // Reconfigure the instance with a valid configuration
+ props.put("conf", "foo"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 2", cs.check());
+ bc.ungetService(ref);
+ under.dispose();
+ }
+
+ @Test
+ public void testTwo() {
+ Properties props = new Properties();
+ props.put("conf", "bar");
+ props.put("instance.name", "under");
+ under = ipojoHelper.createComponentInstance("LFC-Test-Immediate", props);
+
+ assertEquals("check under state", under.getState(), ComponentInstance.INVALID);
+
+ // The conf is incorrect, the PS must not be provided
+ assertFalse("Check service availability -1",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under"));
+
+ // Reconfigure the instance with a correct configuration
+ props.put("conf", "foo");
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under");
+ assertNotNull("Check service availability -2", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state ", cs.check());
+ bc.ungetService(ref);
+ under.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestParentCallback.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestParentCallback.java
new file mode 100644
index 0000000..c819e60
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestParentCallback.java
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestParentCallback extends Common {
+
+ ComponentInstance instance; // Instance under test
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Properties p2 = new Properties();
+ p2.put("instance.name", "fooProvider");
+ fooProvider = ipojoHelper.createComponentInstance("LFCB-FooProviderType-1", p2);
+ fooProvider.stop();
+
+ Properties p1 = new Properties();
+ p1.put("instance.name", "callback");
+ instance = ipojoHelper.createComponentInstance("LFCB-ParentCallbackCheckService", p1);
+
+ }
+
+ @After
+ public void tearDown() {
+ instance.dispose();
+ fooProvider.dispose();
+ instance = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testCallback() {
+ // Check instance is invalid
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper
+ .getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+
+ // Start fooprovider
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+
+ // Check int property
+ assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);
+
+ fooProvider.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ // Check instance validity
+ //id_dep = ((Architecture) osgiHelper.getServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check service providing
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Clean up
+ bc.ungetService(arch_ref);
+ bc.ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/resources/exam.properties b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/resources/exam.properties
new file mode 100644
index 0000000..d8a500d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-callback-test/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/pom.xml
new file mode 100644
index 0000000..528591e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-lifecycle-controller-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableLifecycleControllerTest.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableLifecycleControllerTest.java
new file mode 100644
index 0000000..d41da13
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/ConfigurableLifecycleControllerTest.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.components;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class ConfigurableLifecycleControllerTest implements CheckService {
+
+ // This is both a property and the controller.
+ private boolean m_state;
+
+ public boolean check() {
+ return m_state;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("state", new Boolean(m_state));
+ return props;
+ }
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java
new file mode 100644
index 0000000..3c69e69
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/LifecycleControllerTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class LifecycleControllerTest implements CheckService {
+
+ private boolean m_state = true;
+ private String m_conf;
+
+ public void setConf(String newConf) {
+ if (newConf.equals("foo")) {
+ m_state = true;
+ } else {
+ m_state = false;
+ }
+ }
+
+ public boolean check() {
+ return m_state;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("conf", m_conf);
+ props.put("state", new Boolean(m_state));
+ return props;
+ }
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..63de513
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/main/resources/metadata.xml
@@ -0,0 +1,54 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.LifecycleControllerTest"
+ name="LFC-Test">
+ <provides />
+ <controller field="m_state" />
+ <properties>
+ <property name="conf" field="m_conf" method="setConf" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.LifecycleControllerTest"
+ name="LFC-Test-Immediate" immediate="true" architecture="true">
+ <provides />
+ <controller field="m_state" />
+ <properties>
+ <property name="conf" field="m_conf" method="setConf" />
+ </properties>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.ConfigurableLifecycleControllerTest"
+ name="LFC-Test-Configurable" architecture="true">
+ <provides />
+ <!-- The property and the controller share the same field -->
+ <controller field="m_state" />
+ <properties>
+ <property name="state" field="m_state" />
+ </properties>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..9647dbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ // No custom configuration required.
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurableLifeCycleController.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurableLifeCycleController.java
new file mode 100644
index 0000000..06f4aa4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestConfigurableLifeCycleController.java
@@ -0,0 +1,151 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestConfigurableLifeCycleController extends Common {
+
+ private ComponentInstance under;
+
+ private Factory factory;
+
+
+ @Before
+ public void setUp() {
+ factory = ipojoHelper.getFactory("LFC-Test-Configurable");
+ }
+
+ @Test
+ public void testValidThenInvalid() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties props = new Properties();
+ props.put("instance.name", "under1");
+ props.put("state", "true");
+ under = factory.createComponentInstance(props);
+
+ // The conf is correct, the PS must be provided
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -1", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 1", cs.check());
+ bc.ungetService(ref);
+
+ // Reconfigure the instance
+ props.put("state", "false"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under1"));
+
+ // Reconfigure the instance with a valid configuration
+ props.put("state", "true");
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 2", cs.check());
+ bc.ungetService(ref);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testInValidThenValid() throws Exception {
+ Properties props = new Properties();
+ props.put("instance.name", "under1");
+ props.put("state", "false");
+ under = factory.createComponentInstance(props);
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under1"));
+
+ // Reconfigure the instance
+ props.put("state", "true"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+// Object[] objects = Utils.getServiceObjects(context, Architecture.class.getName(), null);
+// for (int i = 0; i < objects.length; i++) {
+// Architecture a = (Architecture) objects[i];
+// System.out.println(a.getInstanceDescription().getDescription());
+// }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -1", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 1", cs.check());
+ bc.ungetService(ref);
+
+
+ // Reconfigure the instance
+ props.put("state", "false"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under1"));
+
+ // Reconfigure the instance with a valid configuration
+ props.put("state", "true");
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 2", cs.check());
+ bc.ungetService(ref);
+
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java
new file mode 100644
index 0000000..911838d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestImmediateLifeCycleController.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestImmediateLifeCycleController extends Common {
+
+ private ComponentInstance under;
+ private Factory factory;
+
+ @Before
+ public void setUp() {
+ factory = ipojoHelper.getFactory("LFC-Test-Immediate");
+ }
+
+ @Test
+ public void testOne() {
+ Properties props = new Properties();
+ props.put("conf", "foo");
+ props.put("instance.name", "under1");
+ under = ipojoHelper.createComponentInstance("LFC-Test-Immediate", props);
+
+ // The conf is correct, the PS must be provided
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -1", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 1", cs.check());
+ bc.ungetService(ref);
+
+
+ // Reconfigure the instance with a bad configuration
+ props.put("conf", "bar"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under1"));
+
+ // Reconfigure the instance with a valid configuration
+ props.put("conf", "foo"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 2", cs.check());
+ bc.ungetService(ref);
+
+ under.dispose();
+ }
+
+ @Test
+ public void testTwo() {
+ Properties props = new Properties();
+ props.put("conf", "bar");
+ props.put("instance.name", "under2");
+ under = ipojoHelper.createComponentInstance("LFC-Test-Immediate", props);
+
+ assertEquals("check under state", under.getState(), ComponentInstance.INVALID);
+
+ // The conf is incorrect, the PS must not be provided
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under2"));
+
+ // Reconfigure the instance with a correct configuration
+ props.put("conf", "foo");
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under2");
+ assertNotNull("Check service availability -2", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state ", cs.check());
+ bc.ungetService(ref);
+
+
+ under.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestLifeCycleController.java b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestLifeCycleController.java
new file mode 100644
index 0000000..a4c35fd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestLifeCycleController.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestLifeCycleController extends Common {
+
+ private ComponentInstance under;
+
+ private Factory factory;
+
+ @Before
+ public void setUp() {
+ factory = ipojoHelper.getFactory("LFC-Test");
+ }
+
+ @Test
+ public void testOne() {
+ Properties props = new Properties();
+ props.put("conf", "foo");
+ props.put("instance.name", "under1");
+ under = ipojoHelper.createComponentInstance("LFC-Test", props);
+
+ // The conf is correct, the PS must be provided
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -1", ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 1", cs.check());
+ bc.ungetService(ref);
+
+ // Reconfigure the instance with a bad configuration
+ props.put("conf", "bar"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ // The instance should now be invalid
+ assertFalse("Check service availability -2",
+ ipojoHelper.isServiceAvailableByName(CheckService.class.getName(), "under1"));
+
+ // Reconfigure the instance with a valid configuration
+ props.put("conf", "foo"); // Bar is a bad conf
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under1");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state 2", cs.check());
+ bc.ungetService(ref);
+
+ under.dispose();
+ }
+
+ /**
+ * This test must be removed as it is not compliant with osgiHelper. It unregisters a service during the creation of the
+ * service instance, so the returned object is null.
+ */
+ @Test
+ @Ignore("This test must be removed as it is not compliant with osgiHelper. It unregisters a service during the creation" +
+ " of the service instance, so the returned object is null.")
+ public void testTwo() {
+ Properties props = new Properties();
+ props.put("conf", "bar");
+ props.put("instance.name", "under2");
+ under = ipojoHelper.createComponentInstance("LFC-Test", props);
+
+ // The conf is incorrect, but the test can appears only when the object is created : the PS must be provided
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under2");
+ assertNotNull("Check service availability -1", ref);
+
+ System.out.println("CS received : " + osgiHelper.getRawServiceObject(ref));
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertNotNull("Assert CS not null", cs);
+ try {
+ assertFalse("Check state (false)", cs.check());
+ } catch (Throwable e) {
+ fail(e.getMessage());
+ }
+
+ // As soon as the instance is created, the service has to disappear :
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under2");
+ assertNull("Check service availability -2", ref);
+
+ // Reconfigure the instance with a correct configuration
+ props.put("conf", "foo");
+ try {
+ factory.reconfigure(props);
+ } catch (Exception e) {
+ fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
+ }
+
+ ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), "under2");
+ assertNotNull("Check service availability -3", ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check state ", cs.check());
+ bc.ungetService(ref);
+
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/resources/exam.properties b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/resources/exam.properties
new file mode 100644
index 0000000..d8a500d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-lifecycle-controller-test/src/test/resources/exam.properties
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-logger-test/pom.xml
new file mode 100644
index 0000000..a3aa3b1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-logger-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+ <!--
+ Those tests are disabled on equinox, because equinox comes with a broken implementation of the log reader
+ service returning an empty enumeration instead of the collection of logged messages.
+
+ From ExtendedLogReaderServiceFactory.java line 204:
+ Enumeration getLog() {
+ return EMPTY_ENUMERATION;
+ }
+
+ As the tests are based on this, we can't run them on equinox. In addition, registering a log listener is not enough
+ as we miss all messages logged before the registration of the listener.
+ -->
+
+ <profiles>
+ <profile>
+ <id>equinox</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skipTests>true</skipTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
new file mode 100644
index 0000000..5c75293
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyComponent.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+
+public class MyComponent implements MyService {
+
+ public void foo() {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyErroneousComponent.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyErroneousComponent.java
new file mode 100644
index 0000000..91b147a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/MyErroneousComponent.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+
+public class MyErroneousComponent implements MyService {
+
+ public MyErroneousComponent() {
+ throw new NullPointerException("bad");
+ }
+
+ public void foo() {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java
new file mode 100644
index 0000000..94588a2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/MyService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.services;
+
+public interface MyService {
+
+ public void foo();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/component.xml b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/component.xml
new file mode 100644
index 0000000..faceedf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/component.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.MyComponent">
+ <provides/>
+ </component>
+ <instance component="org.apache.felix.ipojo.runtime.core.components.MyComponent"/>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/erroneous-component.xml b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/erroneous-component.xml
new file mode 100644
index 0000000..c8db867
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/main/resources/erroneous-component.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component immediate="true" classname="org.apache.felix.ipojo.runtime.core.components.MyErroneousComponent">
+ <provides/>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..e66f328
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java
new file mode 100644
index 0000000..68b9c49
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestBNDManifestLoggerInfo.java
@@ -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.felix.ipojo.runtime.core;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+public class TestBNDManifestLoggerInfo extends Common {
+
+ private LogReaderService log;
+
+ @Before
+ public void init() {
+ log = (LogReaderService) osgiHelper.getServiceObject(LogReaderService.class.getName(), null);
+ if (log == null) {
+ throw new RuntimeException("No Log Service !");
+ }
+
+ LogService logs = (LogService) osgiHelper.getServiceObject(LogService.class.getName(), null);
+ logs.log(LogService.LOG_WARNING, "Ready");
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ return OptionUtils.combine(options,
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.log").version(asInProject()),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent-WTF")
+ .set("IPOJO-log-level", "info")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
+ )
+ );
+ }
+
+ @Test
+ public void testMessages() throws InterruptedException {
+ osgiHelper.waitForService(Architecture.class, "(architecture.instance=org.apache.felix.ipojo.runtime.core.components.MyComponent-0)", 10000);
+ List<String> messages = getMessages(log.getLog());
+ Assert.assertTrue(messages.contains("Ready"));
+// Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : Instance org.apache.felix.ipojo.runtime.core.components.MyComponent-0 from factory org.apache.felix.ipojo.runtime.core.components.MyComponent created"));
+// Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : New factory created : org.apache.felix.ipojo.runtime.core.components.MyComponent"));
+ }
+
+ private List<String> getMessages(Enumeration<LogEntry> log2) {
+ List<String> list = new ArrayList<String>();
+ while (log2.hasMoreElements()) {
+ LogEntry entry = (LogEntry) log2.nextElement();
+ list.add(entry.getMessage());
+ }
+ return list;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorHandler.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorHandler.java
new file mode 100644
index 0000000..c677323
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestErrorHandler.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ErrorHandler;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.components.MyErroneousComponent;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+@ExamReactorStrategy(PerMethod.class)
+public class TestErrorHandler extends Common {
+
+ @Configuration
+ public Option[] config() throws IOException {
+
+ Option[] options = super.config();
+
+ return OptionUtils.combine(options,
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.log").version(asInProject()),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .set("Ipojo-log-level", "info")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyErroneousComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyErroneousComponent")
+ .set("Ipojo-log-level", "debug")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/erroneous-component.xml")))
+ )
+ );
+ }
+
+ @Test
+ public void testErrorHandlerEmpty() throws InterruptedException, InvalidSyntaxException {
+ MyErrorHandler handler = new MyErrorHandler();
+ bc.registerService(ErrorHandler.class.getName(), handler, null);
+
+ System.out.println(handler.m_errors);
+
+ Assert.assertTrue(handler.m_errors.isEmpty());
+ }
+
+ @Test
+ public void testErrorHandler() throws InterruptedException, InvalidSyntaxException {
+ MyErrorHandler handler = new MyErrorHandler();
+ bc.registerService(ErrorHandler.class.getName(), handler, null);
+
+ Factory factory = ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.components.MyErroneousComponent");
+ assertNotNull(factory);
+ try {
+ factory.createComponentInstance(null);
+ fail("Error expected");
+ } catch (Exception e) {
+ // Error expected.
+ }
+
+ System.out.println(handler.m_errors);
+
+ Assert.assertFalse(handler.m_errors.isEmpty());
+ Assert.assertTrue(handler.m_errors.contains("org.apache.felix.ipojo.runtime.core.components.MyErroneousComponent-0:[org.apache.felix.ipojo.runtime.core.components.MyErroneousComponent-0] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : bad:bad"));
+ }
+
+
+ private class MyErrorHandler implements ErrorHandler {
+
+ private List<String> m_errors = new ArrayList<String>();
+
+ public void onError(ComponentInstance instance, String message,
+ Throwable error) {
+ System.out.println("on Error ! " + instance + " - " + message);
+ if (instance == null) {
+ if (error == null) {
+ m_errors.add("no-instance:" + message);
+ } else {
+ m_errors.add("no-instance:" + message + ":" + error.getMessage());
+ }
+ } else {
+ if (error == null) {
+ m_errors.add(instance.getInstanceName() + ":" + message);
+ } else {
+ m_errors.add(instance.getInstanceName() + ":" + message + ":" + error.getMessage());
+ }
+ }
+ }
+
+ public void onWarning(ComponentInstance instance, String message,
+ Throwable error) {
+ System.out.println("on warning ! " + instance + " - " + message);
+ }
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManifestLoggerInfo.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManifestLoggerInfo.java
new file mode 100644
index 0000000..b03e39b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestManifestLoggerInfo.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+public class TestManifestLoggerInfo extends Common {
+
+ private LogReaderService log;
+
+ @Before
+ public void init() {
+ log = (LogReaderService) osgiHelper.getServiceObject(LogReaderService.class.getName(), null);
+ if (log == null) {
+ throw new RuntimeException("No Log Service !");
+ }
+
+ LogService logs = (LogService) osgiHelper.getServiceObject(LogService.class.getName(), null);
+ logs.log(LogService.LOG_WARNING, "Ready");
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ return OptionUtils.combine(options,
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.log").version(asInProject()),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .set("Ipojo-log-level", "info")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
+ )
+ );
+ }
+
+ @Test
+ public void testMessages() throws InterruptedException, InvalidSyntaxException {
+ Bundle bundle = osgiHelper.getBundle("MyComponent");
+ Assert.assertNotNull(bundle);
+ Assert.assertEquals(Bundle.ACTIVE, bundle.getState());
+
+ ServiceReference r = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(),
+ "org.apache.felix.ipojo.runtime.core.components.MyComponent-0");
+ Assert.assertNotNull(r);
+
+ ServiceReference[] refs = bc.getAllServiceReferences(null, null);
+ for (ServiceReference ref : refs) {
+ System.out.println(ref.getBundle().getBundleId() + " -> " + Arrays.asList((String[]) ref.getProperty(Constants.OBJECTCLASS)));
+ }
+
+
+ Assert.assertNotNull(osgiHelper.getServiceObject(MyService.class.getName(), null));
+
+ osgiHelper.waitForService(MyService.class.getName(), null, 5000);
+ List<String> messages = getMessages(log.getLog());
+ System.out.println(messages);
+ Assert.assertTrue(messages.contains("Ready"));
+// Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : Instance org.apache.felix.ipojo.runtime.core.components.MyComponent-0 from factory org.apache.felix.ipojo.runtime.core.components.MyComponent created"));
+// Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : New factory created : org.apache.felix.ipojo.runtime.core.components.MyComponent"));
+ }
+
+ private List<String> getMessages(Enumeration<LogEntry> log2) {
+ List<String> list = new ArrayList<String>();
+ while (log2.hasMoreElements()) {
+ LogEntry entry = (LogEntry) log2.nextElement();
+ list.add(entry.getMessage());
+ }
+ return list;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerInfo.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerInfo.java
new file mode 100644
index 0000000..629eca3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerInfo.java
@@ -0,0 +1,102 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+
+public class TestSystemLoggerInfo extends Common {
+
+ private LogReaderService log;
+
+ @Before
+ public void init() {
+ log = (LogReaderService) osgiHelper.getServiceObject(LogReaderService.class.getName(), null);
+ if (log == null) {
+ throw new RuntimeException("No Log Service !");
+ }
+
+ LogService logs = (LogService) osgiHelper.getServiceObject(LogService.class.getName(), null);
+ logs.log(LogService.LOG_WARNING, "Ready");
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ return OptionUtils.combine(options,
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.log").version(asInProject()),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(TinyBundles.withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
+ ),
+ systemProperty("ipojo.log.level").value("info")
+ );
+ }
+
+ @Test
+ public void testMessages() throws InterruptedException {
+ List<String> messages = getMessages(log.getLog());
+ Assert.assertTrue(messages.contains("Ready"));
+ Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : Instance org.apache.felix.ipojo.runtime.core.components.MyComponent-0 from factory org.apache.felix.ipojo.runtime.core.components.MyComponent created"));
+ Assert.assertTrue(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : New factory created : org.apache.felix.ipojo.runtime.core.components.MyComponent"));
+ }
+
+ private List<String> getMessages(Enumeration<LogEntry> log2) {
+ List<String> list = new ArrayList<String>();
+ while (log2.hasMoreElements()) {
+ LogEntry entry = (LogEntry) log2.nextElement();
+ list.add(entry.getMessage());
+ }
+ return list;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java
new file mode 100644
index 0000000..0815b4b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-logger-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSystemLoggerWarning.java
@@ -0,0 +1,102 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.components.MyComponent;
+import org.apache.felix.ipojo.runtime.core.services.MyService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+
+public class TestSystemLoggerWarning extends Common {
+
+ private LogReaderService log;
+
+ @Before
+ public void init() {
+ log = (LogReaderService) osgiHelper.getServiceObject(LogReaderService.class.getName(), null);
+ if (log == null) {
+ throw new RuntimeException("No Log Service !");
+ }
+
+ LogService logs = (LogService) osgiHelper.getServiceObject(LogService.class.getName(), null);
+ logs.log(LogService.LOG_WARNING, "Ready");
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ return OptionUtils.combine(options,
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.log").version(asInProject()),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyService.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.services")
+ .build(TinyBundles.withBnd())
+ ),
+ streamBundle(
+ TinyBundles.bundle()
+ .add(MyComponent.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "MyComponent")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/component.xml")))
+ ),
+ systemProperty("ipojo.log.level").value("warning")
+ );
+ }
+
+ @Test
+ public void testMessages() throws InterruptedException {
+ List<String> messages = getMessages(log.getLog());
+ Assert.assertTrue(messages.contains("Ready"));
+ // Not logged.
+ Assert.assertFalse(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : Instance org.apache.felix.ipojo.runtime.core.components.MyComponent-0 from factory org.apache.felix.ipojo.runtime.core.components.MyComponent created"));
+ Assert.assertFalse(messages.contains("[INFO] org.apache.felix.ipojo.runtime.core.components.MyComponent : New factory created : org.apache.felix.ipojo.runtime.core.components.MyComponent"));
+ }
+
+ private List<String> getMessages(Enumeration<LogEntry> log2) {
+ List<String> list = new ArrayList<String>();
+ while (log2.hasMoreElements()) {
+ LogEntry entry = (LogEntry) log2.nextElement();
+ list.add(entry.getMessage());
+ }
+ return list;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/pom.xml
new file mode 100644
index 0000000..0ca423d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-dependency-interceptor-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AdvancedFooConsumer.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AdvancedFooConsumer.java
new file mode 100644
index 0000000..7858711
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/AdvancedFooConsumer.java
@@ -0,0 +1,82 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Enhanced;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A component consuming FooService with a filter requiring interception, and impacting the ranking.
+ */
+@Component(immediate = true)
+@Provides
+public class AdvancedFooConsumer implements CheckService, Setter {
+
+ @Requires(id= "foo", policy = BindingPolicy.DYNAMIC_PRIORITY, proxy = false, filter= "(intercepted=true)",
+ optional = true, nullable = false)
+ private FooService foo;
+
+ private Map<String, Object> props;
+
+ // Will be read by the interceptor to inject only matching provider.
+ @Property(value = "0")
+ private int grade = 0;
+
+ @Override
+ public boolean check() {
+ return foo.foo();
+ }
+
+ @Override
+ public Dictionary getProps() {
+ Properties properties = new Properties();
+ properties.put("props", props);
+ if (foo != null) {
+ properties.put("grade", foo.getGrade());
+ if (foo instanceof Enhanced) {
+ properties.put("enhanced", ((Enhanced) foo).enhance());
+ }
+ }
+ return properties;
+ }
+
+ @Bind(id="foo")
+ public void bind(FooService foo, Map<String, Object> properties) {
+ props = properties;
+ }
+
+ @Modified(id = "foo")
+ public void modified(FooService foo, Map<String, Object> properties) {
+ props = properties;
+ }
+
+ @Override
+ public void set(String newValue) {
+ System.out.println("Setting grade to " + newValue);
+ grade = Integer.parseInt(newValue);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java
new file mode 100644
index 0000000..b6af0e7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooConsumer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Enhanced;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A component consuming FooService
+ */
+@Component(immediate = true)
+@Provides
+public class FooConsumer implements CheckService {
+
+ @Requires(id= "foo", policy = BindingPolicy.DYNAMIC_PRIORITY, proxy = false)
+ private FooService foo;
+
+ private Map<String, Object> props;
+
+ @Override
+ public boolean check() {
+ return foo.foo();
+ }
+
+ @Override
+ public Dictionary getProps() {
+ Properties properties = new Properties();
+ properties.put("props", props);
+ properties.put("grade", foo.getGrade());
+ if (foo instanceof Enhanced) {
+ properties.put("enhanced", ((Enhanced) foo).enhance());
+ }
+ return properties;
+ }
+
+ @Bind(id="foo")
+ public void bind(FooService foo, Map<String, Object> properties) {
+ props = properties;
+ }
+
+ @Modified(id = "foo")
+ public void modified(FooService foo, Map<String, Object> properties) {
+ props = properties;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProvider.java
new file mode 100644
index 0000000..1f82f99
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProvider.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * Provides FooService
+ */
+@Component
+@Provides(properties = @StaticServiceProperty(name="hidden", value = "hidden", type ="string"))
+public class FooProvider implements FooService {
+
+ @ServiceProperty(value = "0")
+ private int grade;
+
+ @Override
+ public boolean foo() {
+ return true;
+ }
+
+ @Override
+ public Properties fooProps() {
+ return null;
+ }
+
+ @Override
+ public int getGrade() {
+ return grade;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AddLocationTrackingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AddLocationTrackingInterceptor.java
new file mode 100644
index 0000000..796f5e5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AddLocationTrackingInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An interceptor adding a property (location) and hiding another property (hidden)
+ * Not instantiated by default.
+ */
+@Component(immediate = true)
+@Provides
+public class AddLocationTrackingInterceptor extends DefaultServiceTrackingInterceptor {
+
+ @ServiceProperty
+ private String target;
+
+
+ @Override
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context,
+ TransformedServiceReference<S> ref) {
+ return ref
+ .addProperty("location", "kitchen") // Because Brian is in the kitchen.
+ .removeProperty("hidden");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AdvancedTrackerAndRankerInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AdvancedTrackerAndRankerInterceptor.java
new file mode 100644
index 0000000..0537aa3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/AdvancedTrackerAndRankerInterceptor.java
@@ -0,0 +1,126 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandlerDescription;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationListener;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An interceptor implements both ranking and tracking interfaces.
+ * It first adds the 'intercepted' property to the services, and then select only the provider having a grade
+ * matching the instance's 'grade' property.
+ */
+@Component(immediate = true)
+@Provides
+public class AdvancedTrackerAndRankerInterceptor extends DefaultDependencyInterceptor implements
+ ServiceTrackingInterceptor, ServiceRankingInterceptor, ConfigurationListener {
+
+ @ServiceProperty
+ private String target;
+
+ @Override
+ public void close(DependencyModel dependency) {
+ super.close(dependency);
+ ConfigurationHandlerDescription handler = (ConfigurationHandlerDescription) dependency.getComponentInstance().getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:properties");
+ handler.removeListener(this);
+ }
+
+ @Override
+ public void open(DependencyModel dependency) {
+ super.open(dependency);
+ ConfigurationHandlerDescription handler = (ConfigurationHandlerDescription) dependency.getComponentInstance().getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:properties");
+ handler.addListener(this);
+ }
+
+ @Override
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ List<ServiceReference> list = new ArrayList<ServiceReference>();
+ Integer grade = getInstanceGrade(dependency);
+ for (ServiceReference ref : matching) {
+ if (grade.equals(ref.getProperty("grade"))) {
+ list.add(ref);
+ }
+ }
+ return list;
+ }
+
+ private Integer getInstanceGrade(DependencyModel dependency) {
+ ConfigurationHandlerDescription handler = (ConfigurationHandlerDescription) dependency.getComponentInstance().getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:properties");
+ return (Integer) handler.getPropertyByName("grade").getCurrentValue();
+ }
+
+ @Override
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context, TransformedServiceReference<S> ref) {
+ return ref.addProperty("intercepted", true);
+ }
+
+ /**
+ * Notifies the managed dependencies of a change in the set of services selected by this interceptor.
+ * The dependency will call the getServiceReferences method to recompute the set of selected services.
+ */
+ public void invalidateSelectedServices() {
+ List<DependencyModel> list = new ArrayList<DependencyModel>();
+ synchronized (this) {
+ list.addAll(dependencies);
+ }
+
+ for (DependencyModel dep : list) {
+ dep.invalidateSelectedServices();
+ }
+ }
+
+ @Override
+ public void configurationChanged(ComponentInstance instance, Map<String, Object> configuration) {
+ invalidateSelectedServices();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java
new file mode 100644
index 0000000..69a5382
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/EnhancingBindingInterceptor.java
@@ -0,0 +1,77 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
+import org.apache.felix.ipojo.runtime.core.test.services.Enhanced;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * A binding interceptor enhancing the service object.
+ */
+@Component(immediate = true)
+@Provides
+public class EnhancingBindingInterceptor extends DefaultDependencyInterceptor implements ServiceBindingInterceptor {
+
+ @ServiceProperty
+ private String target;
+
+ private HashMap<ServiceReference, Object> deps = new HashMap<ServiceReference, Object>();
+
+ @Override
+ public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service) {
+ S proxy = (S) Proxy.newProxyInstance(this.getClass().getClassLoader(),
+ new Class[]{dependency.getSpecification(), Enhanced.class}, new Interceptor(service));
+ deps.put(reference, proxy);
+ return proxy;
+ }
+
+ @Override
+ public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference) {
+ deps.remove(reference);
+ }
+
+ private class Interceptor implements InvocationHandler {
+
+ private final Object service;
+
+ public Interceptor(Object service) {
+ this.service = service;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("enhance")) {
+ return "yo!";
+ }
+ return method.invoke(service, args);
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/FilterRankingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/FilterRankingInterceptor.java
new file mode 100644
index 0000000..4e7a7d6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/FilterRankingInterceptor.java
@@ -0,0 +1,75 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultServiceRankingInterceptor;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * An implementation of the ranking interceptor accepting only services with a 'grade' property and sorting them by
+ * value.
+ */
+@Component(immediate = true)
+@Provides
+public class FilterRankingInterceptor extends DefaultServiceRankingInterceptor implements Setter {
+
+ @ServiceProperty
+ private String target;
+
+ private Comparator<ServiceReference> comparator;
+
+ private boolean inverse = false;
+
+ public FilterRankingInterceptor() {
+ comparator = new GradeComparator();
+ }
+
+ @Override
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ List<ServiceReference> references = new ArrayList<ServiceReference>();
+ for (ServiceReference ref : matching) {
+ if (ref.getProperty("grade") != null) {
+ references.add(ref);
+ }
+ }
+
+ Collections.sort(references, comparator);
+ if (inverse) {
+ Collections.reverse(references);
+ }
+ return references;
+ }
+
+ @Override
+ public void set(String newValue) {
+ inverse = Boolean.parseBoolean(newValue);
+ invalidateSelectedServices();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/GradeComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/GradeComparator.java
new file mode 100644
index 0000000..adb3aa5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/GradeComparator.java
@@ -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.runtime.core.test.interceptors;
+
+import org.osgi.framework.ServiceReference;
+
+import java.util.Comparator;
+
+public class GradeComparator implements Comparator<ServiceReference> {
+ @Override
+ public int compare(ServiceReference ref1, ServiceReference ref2) {
+ Integer grade0;
+ Integer grade1;
+
+ grade0 = (Integer) ref1.getProperty("grade");
+ grade1 = (Integer) ref2.getProperty("grade");
+
+ return grade1.compareTo(grade0); // Best grade first.
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/HidingTrackingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/HidingTrackingInterceptor.java
new file mode 100644
index 0000000..8bb0ffc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/HidingTrackingInterceptor.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An interceptor adding a property (location) and hiding another property (hidden)
+ * Not instantiated by default.
+ */
+@Component(immediate = true)
+@Provides
+public class HidingTrackingInterceptor extends DefaultServiceTrackingInterceptor implements Setter {
+
+ @ServiceProperty
+ private String target;
+
+ private String prop = "hidden";
+
+
+ @Override
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context,
+ TransformedServiceReference<S> ref) {
+ if (ref.contains(prop)) {
+ return null;
+ } else {
+ return ref;
+ }
+ }
+
+ @Override
+ public void set(String newValue) {
+ prop = newValue;
+ invalidateMatchingServices();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/PropertyTrackingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/PropertyTrackingInterceptor.java
new file mode 100644
index 0000000..a68dd05
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/PropertyTrackingInterceptor.java
@@ -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.felix.ipojo.runtime.core.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An interceptor adding a property (location) and hiding another property (hidden)
+ * Not instantiated by default.
+ */
+@Component(immediate = true)
+@Provides
+public class PropertyTrackingInterceptor extends DefaultServiceTrackingInterceptor implements Setter {
+
+ @ServiceProperty
+ private String target;
+
+ private String prop = "kitchen";
+
+
+ @Override
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context,
+ TransformedServiceReference<S> ref) {
+ return ref.addProperty("location", prop);
+ }
+
+ @Override
+ public void set(String newValue) {
+ prop = newValue;
+ invalidateMatchingServices();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java
new file mode 100644
index 0000000..79a623d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/ProxyBindingInterceptor.java
@@ -0,0 +1,100 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.*;
+
+/**
+ * A binding interceptor generating a proxy to monitor the invocations.
+ */
+@Component
+@Provides
+public class ProxyBindingInterceptor extends DefaultDependencyInterceptor implements ServiceBindingInterceptor, CheckService {
+
+ @ServiceProperty
+ private String target;
+
+ private HashMap<ServiceReference, Object> deps = new HashMap<ServiceReference, Object>();
+ private Dictionary data = new Hashtable();
+
+
+ private void increment(String key) {
+ if (data.get(key) == null) {
+ data.put(key, 1);
+ } else {
+ data.put(key, (Integer) data.get(key) + 1);
+ }
+ }
+
+ @Override
+ public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service) {
+ S proxy = (S) Proxy.newProxyInstance(this.getClass().getClassLoader(),
+ new Class[]{dependency.getSpecification()}, new Interceptor(service));
+ deps.put(reference, proxy);
+ increment("bound");
+ return proxy;
+ }
+
+ @Override
+ public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference) {
+ deps.remove(reference);
+ increment("unbound");
+ }
+
+ @Override
+ public boolean check() {
+ return true;
+ }
+
+ @Override
+ public Dictionary getProps() {
+ return data;
+ }
+
+ private class Interceptor implements InvocationHandler {
+
+ private final Object service;
+
+ public Interceptor(Object service) {
+ this.service = service;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ increment(method.getName());
+
+ if (method.getName().equals("toString")) {
+ return this.toString();
+ }
+ return method.invoke(service, args);
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/TrackerAndRankerInterceptor.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/TrackerAndRankerInterceptor.java
new file mode 100644
index 0000000..9f7b4cf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/interceptors/TrackerAndRankerInterceptor.java
@@ -0,0 +1,146 @@
+/*
+ * 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.test.interceptors;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.dependency.interceptors.DefaultDependencyInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An interceptor implements both ranking and tracking interfaces.
+ */
+@Component(immediate = true)
+@Provides
+public class TrackerAndRankerInterceptor extends DefaultDependencyInterceptor implements Setter,
+ ServiceTrackingInterceptor, ServiceRankingInterceptor {
+
+ private static final int HIGH = 1;
+ private static final int LOW = 0;
+
+ @ServiceProperty
+ private String target;
+
+ GradeComparator comparator = new GradeComparator();
+ private int mode = HIGH;
+ private boolean reverse = false;
+
+ @Override
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ List<ServiceReference> references = new ArrayList<ServiceReference>();
+ for (ServiceReference ref : matching) {
+ if (ref.getProperty("grade") != null) {
+ references.add(ref);
+ }
+ }
+
+ Collections.sort(references, comparator);
+ if (reverse) {
+ Collections.reverse(references);
+ }
+ return references;
+ }
+
+ @Override
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ @Override
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context, TransformedServiceReference<S> ref) {
+ // Only accept services having a grade in LOW or HIGH according to the mode.
+ if (mode == HIGH) {
+ if (((Integer) ref.get("grade")) > 3) {
+ return ref;
+ }
+ } else {
+ if (((Integer) ref.get("grade")) <= 3) {
+ return ref;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void set(String newValue) {
+ if (newValue.contains("HIGH")) {
+ mode = HIGH;
+ invalidateMatchingServices();
+ }
+ if (newValue.contains("LOW")) {
+ mode = LOW;
+ invalidateMatchingServices();
+ }
+ if (newValue.contains("REVERSE")) {
+ reverse = true;
+ invalidateSelectedServices();
+ }
+ }
+
+ /**
+ * Notifies the managed dependencies of a change in the set of services selected by this interceptor.
+ * The dependency will call the getServiceReferences method to recompute the set of selected services.
+ */
+ public void invalidateSelectedServices() {
+ List<DependencyModel> list = new ArrayList<DependencyModel>();
+ synchronized (this) {
+ list.addAll(dependencies);
+ }
+
+ for (DependencyModel dep : list) {
+ dep.invalidateSelectedServices();
+ }
+ }
+
+ /**
+ * Notifies the managed dependencies of a change in the set of services accepted by this interceptor.
+ * The dependency will call the accept method to recompute the set of matching services.
+ */
+ public void invalidateMatchingServices() {
+ List<DependencyModel> list = new ArrayList<DependencyModel>();
+ synchronized (this) {
+ list.addAll(dependencies);
+ }
+
+ for (DependencyModel dep : list) {
+ dep.invalidateMatchingServices();
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..2ed95ff
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.services;
+
+import java.util.Dictionary;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Dictionary getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java
new file mode 100644
index 0000000..32333c4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Enhanced.java
@@ -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.felix.ipojo.runtime.core.test.services;
+
+/**
+ * An interface added on the fly to the service object.
+ */
+public interface Enhanced {
+
+ public String enhance();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..7cd1ac2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ public int getGrade();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Setter.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Setter.java
new file mode 100644
index 0000000..655040d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Setter.java
@@ -0,0 +1,28 @@
+/*
+ * 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.test.services;
+
+/**
+ * A simple interface to set a property.
+ */
+public interface Setter {
+
+ public void set(String newValue);
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
new file mode 100644
index 0000000..3f89bbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -0,0 +1,40 @@
+/*
+ * 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.test.dependencies;
+
+import org.ops4j.pax.exam.Option;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[] {
+ wrappedBundle(maven("org.easytesting", "fest-assert").versionAsInProject()),
+ wrappedBundle(maven("org.easytesting", "fest-util").versionAsInProject())
+ };
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java
new file mode 100644
index 0000000..853c419
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestBindingInterceptors.java
@@ -0,0 +1,203 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks binding interceptors.
+ */
+public class TestBindingInterceptors extends Common {
+
+ private ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ provider = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooProvider");
+ }
+
+ @Test
+ public void testProxyBindingInterceptorBeforeInstanceCreation() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".ProxyBindingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components" +
+ ".FooConsumer");
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")",
+ 1000, true);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ assertThat(check.check());
+
+ // Extract monitored data
+ CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+ "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
+
+ assertThat(checkService).isNotNull();
+ assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+ assertThat(checkService.getProps().get("foo")).isEqualTo(1);
+
+ provider.dispose();
+
+ assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+ assertThat(checkService.getProps().get("unbound")).isEqualTo(1);
+ }
+
+ /**
+ * Same as previous but the interceptor arrives after the instance.
+ */
+ @Test
+ public void testProxyBindingInterceptorAfterInstanceCreation() {
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components" +
+ ".FooConsumer");
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")",
+ 1000, true);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ assertThat(check.check());
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".ProxyBindingInterceptor", configuration);
+
+ // Extract monitored data
+ CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+ "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
+
+ // Nothing was intercepted.
+ assertThat(checkService).isNotNull();
+ assertThat(checkService.getProps().get("bound")).isNull();
+ assertThat(checkService.getProps().get("foo")).isNull();
+
+ // Force rebinding.
+ provider.stop();
+ provider.start();
+
+ check.check();
+
+ // Things should have been intercepted
+ assertThat(checkService).isNotNull();
+ assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+ assertThat(checkService.getProps().get("foo")).isEqualTo(1);
+
+ provider.dispose();
+
+ // Two unget calls, as we intercepted the first one (provider.stop()).
+ assertThat(checkService.getProps().get("unbound")).isEqualTo(2);
+ }
+
+ /**
+ * Checks that two interceptors are called sequentially.
+ */
+ @Test
+ public void testWithTwoInterceptors() {
+ // First, only one interceptor.
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".ProxyBindingInterceptor", configuration);
+
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components" +
+ ".FooConsumer");
+
+ ServiceReference ref = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")",
+ 1000, true);
+ CheckService check = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ assertThat(check.check());
+
+ // Create the second interceptor, but it's too late to modify the first binding.
+ configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".EnhancingBindingInterceptor", configuration);
+
+ assertThat(check.getProps().get("enhanced")).isNull();
+
+ // Extract monitored data
+ CheckService checkService = osgiHelper.getServiceObject(CheckService.class,
+ "(factory.name=org.apache.felix.ipojo.runtime.core.test.interceptors.ProxyBindingInterceptor)");
+
+ assertThat(checkService).isNotNull();
+ assertThat(checkService.getProps().get("bound")).isEqualTo(1);
+ assertThat(checkService.getProps().get("foo")).isEqualTo(1);
+
+ // Force re-binding.
+ provider.stop();
+ provider.start();
+
+ assertThat(check.getProps().get("enhanced")).isNotNull();
+ }
+
+ @Test
+ public void testArchitecture() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".interceptors.ProxyBindingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")",
+ 1000, true);
+
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("servicebindinginterceptor");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("target=\"(dependency.id=foo)\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("instance.name=\"" + interceptor.getInstanceName() + "\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("bundle.id=\"" + getTestBundle().getBundleId() + "\"");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCombinationOfInterceptors.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCombinationOfInterceptors.java
new file mode 100644
index 0000000..df9f9fe
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCombinationOfInterceptors.java
@@ -0,0 +1,129 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks the combination of tracking and ranking interceptors.
+ *
+ * First, the tracking interceptor selects the references, it also transforms them.
+ * Then, the ranking interceptor sorts the remaining references.
+ */
+public class TestCombinationOfInterceptors extends Common {
+
+ private ComponentInstance provider1;
+ private ComponentInstance provider2;
+ private ComponentInstance provider3;
+ private ComponentInstance provider4;
+ private ComponentInstance provider5;
+ private ComponentInstance provider6;
+
+ @Test
+ public void testCombination() {
+
+ provider1 = provider(0);
+ provider2 = provider(1);
+ provider3 = provider(2);
+ provider4 = provider(3);
+ provider5 = provider(4);
+ provider6 = provider(5);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".TrackerAndRankerInterceptor", configuration);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ // Check we are using provider 2
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(5);
+
+ provider6.dispose();
+
+ assertThat(check.getProps().get("grade")).isEqualTo(4);
+
+ // Change range
+ Setter setter = osgiHelper.getServiceObject(Setter.class);
+ setter.set("LOW REVERSE");
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+ }
+
+ @Test
+ public void testAdvanced() {
+
+ provider1 = provider(0);
+ provider2 = provider(0);
+ provider3 = provider(1);
+ provider4 = provider(1);
+ provider5 = provider(2);
+ provider6 = provider(2);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".AdvancedTrackerAndRankerInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.AdvancedFooConsumer");
+
+ // Check we are using provider 0
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+
+ Dictionary conf = new Hashtable();
+ conf.put("grade", "1");
+ instance.reconfigure(conf);
+
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ conf.put("grade", "2");
+ instance.reconfigure(conf);
+ assertThat(check.getProps().get("grade")).isEqualTo(2);
+
+ conf.put("grade", "3");
+ instance.reconfigure(conf);
+ assertThat(check.getProps().get("grade")).isNull();
+ }
+
+
+ private ComponentInstance provider(int i) {
+ Dictionary<String, String> configuration = new Hashtable<String, String>();
+ configuration.put("grade", Integer.toString(i));
+ return ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooProvider",
+ configuration);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestHidingServices.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestHidingServices.java
new file mode 100644
index 0000000..b67af97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestHidingServices.java
@@ -0,0 +1,133 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks Tracking interceptor hiding services
+ */
+public class TestHidingServices extends Common {
+
+ private ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ provider = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooProvider");
+ }
+
+ @Test
+ public void testHidingServiceAndReconfiguration() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".HidingTrackingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ // The provider is rejected => Invalid instance
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.INVALID);
+
+ Setter setter = osgiHelper.getServiceObject(Setter.class, null);
+ setter.set("toto");
+
+ // The provider is now accepted
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.VALID);
+ }
+
+ /**
+ * Same as previous but the interceptor arrives after the instance.
+ */
+ @Test
+ public void testHidingAServiceAfterItsBinding() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.VALID);
+
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".interceptors.HidingTrackingInterceptor", configuration);
+
+ // The provider is rejected => Invalid instance
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.INVALID);
+
+ Setter setter = osgiHelper.getServiceObject(Setter.class, null);
+ setter.set("toto");
+
+ // The provider is now accepted
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.VALID);
+
+ setter.set("hidden");
+
+ // The provider is rejected => Invalid instance
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.INVALID);
+
+ interceptor.dispose();
+
+ // The provider is now accepted
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.VALID);
+ }
+
+ @Test
+ public void testArchitecture() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ assertThat(instance.getState()).isEqualTo(ComponentInstance.VALID);
+
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".interceptors.HidingTrackingInterceptor", configuration);
+
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("servicetrackinginterceptor");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("target=\"(dependency.id=foo)\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("instance.name=\"" + interceptor.getInstanceName() + "\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("bundle.id=\"" + getTestBundle().getBundleId() + "\"");
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestInterceptorsOnSeveralDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestInterceptorsOnSeveralDependencies.java
new file mode 100644
index 0000000..a99c89c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestInterceptorsOnSeveralDependencies.java
@@ -0,0 +1,94 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Map;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks Tracking interceptor bound to several dependencies.
+ */
+public class TestInterceptorsOnSeveralDependencies extends Common {
+
+ private ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ provider = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooProvider");
+ }
+
+ @Test
+ public void testBeingBoundToSeveralDependencies() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".interceptors.PropertyTrackingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance1 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ ComponentInstance instance2 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ assertThat(instance1.getState()).isEqualTo(ComponentInstance.VALID);
+ assertThat(instance2.getState()).isEqualTo(ComponentInstance.VALID);
+
+ final ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(),
+ instance1.getInstanceName());
+ final ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(),
+ instance2.getInstanceName());
+
+ CheckService cs1 = (CheckService) osgiHelper.getRawServiceObject(ref1);
+ CheckService cs2 = (CheckService) osgiHelper.getRawServiceObject(ref2);
+
+ @SuppressWarnings("unchecked") Map<String, ?> props1 = (Map<String, ?>) cs1.getProps().get("props");
+ @SuppressWarnings("unchecked") Map<String, ?> props2 = (Map<String, ?>) cs2.getProps().get("props");
+ assertThat(props1.get("location")).isEqualTo("kitchen");
+ assertThat(props2.get("location")).isEqualTo("kitchen");
+
+ Setter setter = osgiHelper.getServiceObject(Setter.class, null);
+ setter.set("bedroom");
+
+ props1 = (Map<String, ?>) cs1.getProps().get("props");
+ props2 = (Map<String, ?>) cs2.getProps().get("props");
+ assertThat(props1.get("location")).isEqualTo("bedroom");
+ assertThat(props2.get("location")).isEqualTo("bedroom");
+
+ interceptor.dispose();
+
+ props1 = (Map<String, ?>) cs1.getProps().get("props");
+ props2 = (Map<String, ?>) cs2.getProps().get("props");
+ assertThat(props1.get("location")).isNull();
+ assertThat(props2.get("location")).isNull();
+
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestRankingServices.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestRankingServices.java
new file mode 100644
index 0000000..c405eb1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestRankingServices.java
@@ -0,0 +1,221 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.Setter;
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks Tracking interceptor transforming services
+ */
+public class TestRankingServices extends Common {
+
+ private ComponentInstance provider1;
+ private ComponentInstance provider2;
+
+ @Test
+ public void testRanking() {
+
+ // Provider with grade 0 first
+ provider1 = provider(0);
+ provider2 = provider(1);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".FilterRankingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ // Check we are using provider 2
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ provider2.dispose();
+
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+ }
+
+ @Test
+ public void testRankingWhenInterceptorIsComingAfterTheBattle() {
+
+ // Provider with grade 0 first
+ provider1 = provider(0);
+ provider2 = provider(1);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".FilterRankingInterceptor", configuration);
+
+ // Check we are using provider 2
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ provider2.dispose();
+
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+ }
+
+ @Test
+ public void testRankingChanges() {
+
+ // Provider with grade 0 first
+ provider1 = provider(0);
+ provider2 = provider(1);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".FilterRankingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ // Check we are using provider 2
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ Setter setter = osgiHelper.getServiceObject(Setter.class);
+ setter.set("true");
+
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+ }
+
+ @Test
+ public void testRestorationOfTheComparatorWhenTheInterceptorLeaves() {
+
+ // Provider with grade 0 first
+ provider1 = provider(0);
+ provider2 = provider(1);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".test.interceptors.FilterRankingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ // Check we are using provider 2
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ interceptor.dispose();
+
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+ }
+
+ @Test
+ public void testDynamicServices() {
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".FilterRankingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance consumer = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.INVALID);
+
+ provider1 = provider(0);
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.VALID);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+
+ provider2 = provider(1);
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.VALID);
+ check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(1);
+
+ provider2.dispose();
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.VALID);
+ check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.getProps().get("grade")).isEqualTo(0);
+
+ provider1.dispose();
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.INVALID);
+ }
+
+ @Test
+ public void testArchitecture() {
+ // Provider with grade 0 first
+ provider1 = provider(0);
+ provider2 = provider(1);
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core" +
+ ".test.interceptors.FilterRankingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ // Check we are using provider 2
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("servicerankinginterceptor");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("target=\"(dependency.id=foo)\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("instance.name=\"" + interceptor.getInstanceName() + "\"");
+ assertThat(instance.getInstanceDescription().getDescription().toString()).contains
+ ("bundle.id=\"" + getTestBundle().getBundleId() + "\"");
+ }
+
+ private ComponentInstance provider(int i) {
+ Dictionary<String, String> configuration = new Hashtable<String, String>();
+ configuration.put("grade", Integer.toString(i));
+ return ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooProvider",
+ configuration);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java
new file mode 100644
index 0000000..e71b5ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-interceptor-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestTransformingServices.java
@@ -0,0 +1,177 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks Tracking interceptor transforming services
+ */
+public class TestTransformingServices extends Common {
+
+ private ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ provider = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooProvider");
+ }
+
+ @Test
+ public void testTransformationOfFoo() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".AddLocationTrackingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.FooConsumer");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.check());
+ @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+ }
+
+ /**
+ * Same as previous but the interceptor arrives after the instance.
+ */
+ @Test
+ public void testDelayedTransformationOfFoo() {
+ // Create the FooConsumer
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components" +
+ ".FooConsumer");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.check());
+ @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isNull();
+ assertThat(props.get("hidden")).isNotNull();
+
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".AddLocationTrackingInterceptor", configuration);
+
+ assertThat(check.check());
+ props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+ }
+
+ /**
+ * The interceptor makes the instance valid.
+ */
+ @Test
+ public void testTransformationMakingFilterMatch() {
+ // Create the FooConsumer
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(location=kitchen)");
+ configuration.put("requires.filters", filters);
+ ComponentInstance consumer = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer", configuration);
+
+ // Invalid instance
+ assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.INVALID);
+
+ // Create the interceptor
+ Properties config = new Properties();
+ config.put("target", "(dependency.id=foo)");
+ ComponentInstance interceptor = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".interceptors.AddLocationTrackingInterceptor", config);
+
+ assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.VALID);
+
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+
+ assertThat(check.check());
+ Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+
+ // Removing the interceptor should revert to the base set.
+ interceptor.dispose();
+ System.out.println(consumer.getInstanceDescription().getDescription());
+ assertThat(consumer.getInstanceDescription().getState()).isEqualTo(ComponentInstance.INVALID);
+ }
+
+ /**
+ * Checks the behavior when services arrives and leaves.
+ */
+ @Test
+ public void testTransformationOfDynamicFoo() {
+ // Create the interceptor
+ Properties configuration = new Properties();
+ configuration.put("target", "(dependency.id=foo)");
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test.interceptors" +
+ ".AddLocationTrackingInterceptor", configuration);
+
+ // Create the FooConsumer
+ ComponentInstance consumer = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooConsumer");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 1000, true);
+ CheckService check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.check());
+ @SuppressWarnings("unchecked") Map<String, ?> props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+
+ // Create another provider
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.FooProvider");
+
+ check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.check());
+ props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+
+ // Provider 1 leaves
+ provider.dispose();
+
+ // The second provider is also transformed.
+ check = osgiHelper.getServiceObject(CheckService.class);
+ assertThat(check.check());
+ props = (Map<String, ?>) check.getProps().get("props");
+ assertThat(props.get("location")).isEqualTo("kitchen");
+ assertThat(props.get("hidden")).isNull();
+
+ provider2.dispose();
+
+ System.out.println(consumer.getInstanceDescription().getDescription());
+
+ assertThat(consumer.getState()).isEqualTo(ComponentInstance.INVALID);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/pom.xml
new file mode 100644
index 0000000..e556c18
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-dependency-optional-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..99a99be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
@@ -0,0 +1,65 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if (props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+ public void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
new file mode 100644
index 0000000..b708d80
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+
+ int modified = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapB", mapB);
+ props.put("dictB", dictB);
+ props.put("mapU", mapU);
+ props.put("dictU", dictU);
+ if (fs != null) {
+ // If nullable = false and proxy, a runtime exception may be launched here
+ // catch the exception and add this to props.
+ try {
+ props.put("exception", Boolean.FALSE); // Set exception to false for checking.
+ props.put("result", fs.foo());
+ props.put("boolean", fs.getBoolean());
+ props.put("int", fs.getInt());
+ props.put("long", fs.getLong());
+ props.put("double", fs.getDouble());
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ } catch (RuntimeException e) {
+ props.put("exception", Boolean.TRUE);
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+
+
+ // Add modified
+ props.put("modified", modified);
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ public void voidModify() {
+ modified ++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ objectB++;
+ }
+
+ protected void objectModify(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! [" + modified + "]");
+ return;
+ }
+ modified++;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void refModify(ServiceReference sr) {
+ if(sr != null) { modified++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null) { bothB++; }
+ }
+
+ public void bothModify(FooService o, ServiceReference sr) {
+ if(sr != null && o != null) { modified++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+
+ protected void propertiesDictionaryModify(FooService o, Dictionary props) {
+ if(props != null && o != null && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+
+ protected void propertiesMapModify(FooService o, Map props) {
+ if(props != null && o != null && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
new file mode 100644
index 0000000..db65a4c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+import java.util.*;
+
+public class CollectionCheckService implements CheckService {
+
+ Collection fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
new file mode 100644
index 0000000..4100659
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
new file mode 100644
index 0000000..cccb9be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
@@ -0,0 +1,109 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
new file mode 100644
index 0000000..95cb237
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType2 implements FooService {
+
+ private int m_bar; // Service property.
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static int count = 0;
+
+
+ public boolean foo() {
+ // Update
+ if (m_foo.equals("foo")) {
+ m_foo = "bar";
+ } else {
+ m_foo = "foo";
+ }
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
new file mode 100644
index 0000000..ec7207f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FooServiceDefaultImpl implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 5;
+ }
+
+ public int getInt() {
+ return 5;
+ }
+
+ public long getLong() {
+ return 5;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
new file mode 100644
index 0000000..4bbdeaf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
@@ -0,0 +1,184 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class ListCheckService implements CheckService {
+
+ List fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..2d3a6fa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
@@ -0,0 +1,134 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if(fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+
+ if(fs != null) {
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs = o;
+ }
+ protected void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs = (FooService) context.getService(sr);
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothB++; }
+ fs = o;
+ }
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothU++; }
+ fs = null;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs = null;
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
new file mode 100644
index 0000000..ff8800e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+
+import java.util.*;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB = 0;
+ int mapU = 0;
+ int dictB = 0, dictU=0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) { return null; }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", check());
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapU", mapU);
+ props.put("mapB", mapB);
+ props.put("dictU", dictU);
+ props.put("dictB", dictB);
+ props.put("boolean", getBoolean());
+ props.put("int", getInt());
+ props.put("long", getLong());
+ props.put("double", getDouble());
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs.add(o);
+ }
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs.add(context.getService(sr));
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs.add(o);
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs.remove(o);
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs.add(o);
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs.remove(o);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
new file mode 100644
index 0000000..0e3007d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..63eb7bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int binded;
+
+ public MultipleFilterCheckSubscriber(){
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(binded));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ binded++;
+ }
+ private void Unbind() {
+ binded--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
new file mode 100644
index 0000000..4fd100a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
new file mode 100644
index 0000000..9ac13e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() {
+ return m_grade; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
new file mode 100644
index 0000000..f25a95f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+public class SetCheckService implements CheckService {
+
+ Set fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
new file mode 100644
index 0000000..fe3e00b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
@@ -0,0 +1,159 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+import java.util.Vector;
+
+public class VectorCheckService implements CheckService {
+
+ Vector fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ // simpleB++;
+ }
+
+ public void voidUnbind() {
+ // simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
new file mode 100644
index 0000000..5295912
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ FooService fs2;
+
+ FooService[] fss;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("fs", new Integer(fs.getInt()));
+ props.put("fs2", new Integer(fs2.getInt()));
+
+ int[] grades = new int[fss.length];
+
+ for (int i = 0; i < grades.length; i++) {
+ grades[i] = fss[i].getInt();
+ }
+
+ props.put("fss", grades);
+
+ return props;
+ }
+
+ void bind(FooService svc) {
+ fs2 = svc;
+ }
+
+ void unbind(FooService svc) {
+ fs2 = null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
new file mode 100644
index 0000000..3d09a97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.comparator;
+
+import org.osgi.framework.ServiceReference;
+
+import java.util.Comparator;
+
+public class GradeComparator implements Comparator {
+
+ public int compare(Object arg0, Object arg1) {
+ ServiceReference ref0 = null;
+ ServiceReference ref1 = null;
+ Integer grade0 = null;
+ Integer grade1 = null;
+ if (arg0 instanceof ServiceReference) {
+ ref0 = (ServiceReference) arg0;
+ grade0 = (Integer) ref0.getProperty("grade");
+ }
+ if (arg1 instanceof ServiceReference) {
+ ref1 = (ServiceReference) arg1;
+ grade1 = (Integer) ref1.getProperty("grade");
+ }
+
+ if (ref0 != null && ref1 != null
+ && grade0 != null && grade1 != null) {
+ return grade1.compareTo(grade0); // Best grade first.
+ } else {
+ return 0; // Equals
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
new file mode 100644
index 0000000..0309800
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class GradedFooServiceProvider implements FooService {
+
+
+ private int grade;
+
+ public boolean foo() {
+ return grade > 0;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return grade;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
new file mode 100644
index 0000000..9f8a9b2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.test.components.exceptions;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A component supporting exception when no services are available.
+ */
+@Component
+@Provides
+public class ExceptionAwareCheckServiceProvider implements CheckService {
+
+ @Requires(id="foo", optional = true, exception = NoServiceException.class)
+ private FooService fs;
+ private int bind;
+ private int unbind;
+
+ @Bind(id = "foo")
+ public void bindFoo(FooService fs) {
+ if (fs != null) {
+ bind++;
+ }
+ }
+
+ public void unbindFoo(FooService fs) {
+ if (fs != null) {
+ unbind++;
+ }
+ }
+
+ @Override
+ public boolean check() {
+ try {
+ fs.foo();
+ return true; // always return true, to detect the exception case.
+ } catch (NoServiceException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public Properties getProps() {
+ Properties properties = new Properties();
+ properties.put("bind", bind);
+ properties.put("unbind", unbind);
+ return properties;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java
new file mode 100644
index 0000000..d21d215
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.components.exceptions;
+
+/**
+ * Class used to test the 'exception' attribute.
+ */
+public class NoServiceException extends RuntimeException {
+
+ public NoServiceException(String message) {
+ super(message);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
new file mode 100644
index 0000000..91c33e7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
@@ -0,0 +1,90 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckProvider implements CheckService, FooService {
+
+ private String m_toto;
+
+ private int bind;
+
+ private int unbind;
+
+ public FilterCheckProvider() {
+ m_toto = "A";
+ }
+
+ public boolean check() {
+ if (m_toto.equals("A")) {
+ m_toto = "B";
+ return true;
+ } else {
+ m_toto = "A";
+ return false;
+ }
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bind - unbind));
+ return null;
+ }
+
+ private void Bind() {
+ bind++;
+ }
+
+ private void Unbind() {
+ unbind++;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
new file mode 100644
index 0000000..5ffa4bd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components.filter;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckSubscriber implements CheckService {
+
+ private FooService m_foo;
+
+ private int bound;
+
+ public FilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ m_foo.foo();
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Nullable", new Boolean(m_foo instanceof Nullable));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..0ee898c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int bound;
+
+ public MultipleFilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
new file mode 100644
index 0000000..646bfbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C1 implements Call {
+
+ public String callMe() {
+ return "called";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
new file mode 100644
index 0000000..b4c0c88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C2 {
+
+ private Call c1;
+
+ public String authenticate() {
+ return c1.callMe();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
new file mode 100644
index 0000000..7f71de4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.components.inner;
+
+public class C3 {
+
+ private C2 c2;
+
+ public MyFilter getFilter() {
+ return new MyFilter() {
+ public String authenticate() {
+ System.out.println("My Filter ...");
+ String r = c2.authenticate();
+ System.out.println(" ... " + r);
+ return r;
+ }
+ };
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
new file mode 100644
index 0000000..e3e64cd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components.inner;
+
+public interface MyFilter {
+
+ public String authenticate();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
new file mode 100644
index 0000000..398d342
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components.optional;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.service.log.LogService;
+
+
+@Component(immediate=true, name="optional-log-cons")
+public class MyComponent {
+
+ @Requires(optional=true, proxy=false)
+ private LogService log;
+
+
+ public MyComponent() {
+ System.out.println("Created ! : " + (log instanceof Nullable) + " - " + log);
+ log.log(LogService.LOG_INFO, "Created !");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
new file mode 100644
index 0000000..a89dd43
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
new file mode 100644
index 0000000..f55cfcc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
@@ -0,0 +1,91 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
new file mode 100644
index 0000000..93c3737
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..5b13c7b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ if (fs != null) {
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs = o;
+ }
+
+ protected void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs = (FooService) context.getService(sr);
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ fs = o;
+ }
+
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothU++;
+ }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
new file mode 100644
index 0000000..05481af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs.add(o);
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs.add(context.getService(sr));
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
new file mode 100644
index 0000000..f437e09
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
new file mode 100644
index 0000000..e2f9bc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return m_grade;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
new file mode 100644
index 0000000..14c69c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceDelegator implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceDelegator(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
new file mode 100644
index 0000000..ebc94c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceGetAndDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceGetAndDelegate(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ fs.foo();
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ fs.getBoolean();
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
new file mode 100644
index 0000000..6db5841
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceNoDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ private BundleContext context;
+
+ public CheckServiceNoDelegate(BundleContext bc) {
+ context = bc;
+ helper = new Helper(context, fs);
+ }
+
+ public void start() {
+ helper.publish();
+ }
+
+ public void stop() {
+ helper.unpublish();
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
new file mode 100644
index 0000000..5c04dac
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+
+import java.util.AbstractMap;
+import java.util.Properties;
+
+public class CheckServiceUsingStringService implements CheckService {
+
+ private String string;
+ private AbstractMap map;
+
+
+ public CheckServiceUsingStringService() {
+ System.out.println("Service : " + string);
+ System.out.println("Map : " + map);
+ }
+
+ public boolean check() {
+ return string != null
+ && map != null;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
new file mode 100644
index 0000000..dd86961
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+public class Helper implements CheckService {
+
+
+ private FooService fs;
+ private BundleContext context;
+ private ServiceRegistration reg;
+
+ public Helper(BundleContext bc, FooService svc) {
+ fs = svc;
+ context = bc;
+ }
+
+ public void publish() {
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_PID, "Helper");
+ context.registerService(CheckService.class, this, props);
+ reg = context.registerService(CheckService.class.getName(), this, props);
+ }
+
+ public void unpublish() {
+ if (reg != null) {
+ reg.unregister();
+ }
+ reg = null;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ fs.getBoolean();
+ props.put("helper.fs", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
new file mode 100644
index 0000000..3f4e34c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
@@ -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.felix.ipojo.runtime.core.test.services;
+
+public interface Call {
+
+
+ public String callMe();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..e4366ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..9b8e12b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-comparator.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-comparator.xml
new file mode 100644
index 0000000..1fb7e18
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-comparator.xml
@@ -0,0 +1,55 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradedFooServiceProvider"
+ name="COMPARATOR-gradedFooProvider">
+ <provides>
+ <property field="grade"/>
+ </provides>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicCheckService">
+ <provides/>
+ <requires field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicPriorityCheckService">
+ <provides/>
+ <requires policy="dynamic-priority" field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-filter.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-filter.xml
new file mode 100644
index 0000000..975b5b5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-filter.xml
@@ -0,0 +1,141 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <!-- Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimpleFilterCheckServiceProvider" architecture="true">
+ <provides>
+ <property field="m_toto" name="toto" value="A" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFromCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" from="A" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimplePIDCheckServiceProvider" architecture="true">
+ <provides>
+ <property type="String" name="service.pid" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1"
+ optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate filter Dependencies-->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Aggregate Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false"
+ optional="true">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-policies.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-policies.xml
new file mode 100644
index 0000000..852763f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata-policies.xml
@@ -0,0 +1,283 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Static Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Static Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <!-- Static Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticSimpleMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticVoidMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMRefMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Dynamic-Priority -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.RankedFooProviderType1"
+ name="RankedFooProviderType" architecture="true">
+ <provides>
+ <property field="m_grade" name="service.ranking"/>
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..e42a2eb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/resources/metadata.xml
@@ -0,0 +1,1083 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<!--
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType1"
+ name="FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Simple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" proxy="true"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <!-- Simple & Optional Dependencies with default-implementation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DISimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="BothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedBothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="MapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedMapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="DictMultipleCheckServiceProvider" architecture="true" >
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedDictMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefMultipleCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MBothMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MMapMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MDictMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as List -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="SimpleListCheckServiceProvider" architecture="true">
+ <requires proxy="false"
+ field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="OptionalListCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false"
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedSimpleListCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedOptionalListCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Vector -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="SimpleVectorCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind"/>
+ <callback type="unbind" method="objectUnbind"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="OptionalVectorCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Set -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="SimpleSetCheckServiceProvider" architecture="true">
+ <requires proxy="false" field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="OptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedSimpleSetCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedOptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Collection -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="SimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedSimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="OptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedOptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+
+
+ <!-- Modify method test -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType2"
+ name="FooProviderType-Updatable" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" value="foo"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ <callback type="modified" method="voidModify"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ <callback type="modified" method="objectModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ <callback type="modified" method="refModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ <callback type="modified" method="bothModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ <callback type="modified" method="propertiesMapModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ <callback type="modified" method="propertiesDictionaryModify" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Proxy Tests -->
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceGetAndDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceNoDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceUsingStringService"
+ immediate="true">
+ <provides/>
+ <requires field="string"/>
+ <requires field="map"/>
+ </component>
+
+ <!-- Inner + Proxy mix -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C1">
+ <provides/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C2">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C2"/>
+ <requires field="c1"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C3">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C3"/>
+ <requires field="c2"/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
new file mode 100644
index 0000000..67029d0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.dependencies;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ eventadmin()
+ };
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.test.components.inner"
+ );
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ // Use an old version of the event admin to avoid import package issues on KF
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.2.10"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin",
+ "1.8.0").versionAsInProject());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestDelayedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestDelayedOptionalDependencies.java
new file mode 100644
index 0000000..2920868
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestDelayedOptionalDependencies.java
@@ -0,0 +1,365 @@
+/*
+ * 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.test.dependencies.di;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestDelayedOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("DISimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("DIVoidOptionalCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("DIObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("DIRefOptionalCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("DIBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testSimple() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 5);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 5);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 5.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance1.stop();
+ }
+
+ @Test
+ public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 5);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 5);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 5.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance2.stop();
+ }
+
+ @Test
+ public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test
+ public void testRef() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test
+ public void testBoth() {
+ instance5.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodDelayedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodDelayedOptionalDependencies.java
new file mode 100644
index 0000000..5fa3d5b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodDelayedOptionalDependencies.java
@@ -0,0 +1,235 @@
+/*
+ * 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.test.dependencies.di;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestMethodDelayedOptionalDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("DIMObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("DIMRefOptionalCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("DIMBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test
+ public void testRef() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test
+ public void testBoth() {
+ instance5.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodOptionalDependencies.java
new file mode 100644
index 0000000..b4b0bb0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestMethodOptionalDependencies.java
@@ -0,0 +1,275 @@
+/*
+ * 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.test.dependencies.di;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodOptionalDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("DIMObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("DIMRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("DIMBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testObject() {
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestOptionalDependencies.java
new file mode 100644
index 0000000..9e774c7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/di/TestOptionalDependencies.java
@@ -0,0 +1,399 @@
+/*
+ * 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.test.dependencies.di;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("DISimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("DIVoidOptionalCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("DIObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("DIRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("DIBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 5);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 5);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 5.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is there
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 5);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 5);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 5.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -3 (" + ((Integer) props.get("voidU")) + ")", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 3", props.get("object"));
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 5);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 5);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 5.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2 (" + ((Integer) props.get("objectB")).intValue() + ")", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.java
new file mode 100644
index 0000000..e0e4be7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.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.test.dependencies.exceptions;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Checks the behavior of the exception attribute.
+ */
+public class TestDependenciesWithExceptions extends Common {
+
+ ComponentInstance consumer;
+ ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ provider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ provider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Consumer");
+ consumer = ipojoHelper
+ .getFactory("org.apache.felix.ipojo.runtime.core.test.components.exceptions.ExceptionAwareCheckServiceProvider")
+ .createComponentInstance(i1);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ consumer.dispose();
+ provider.dispose();
+ consumer = null;
+ provider = null;
+ }
+
+ /**
+ * A simple test checking that the exception is thrown.
+ */
+ @Test
+ public void testExceptionWhenServiceUnavailable() {
+ assertNull(osgiHelper.getServiceObject(FooService.class));
+ osgiHelper.waitForService(CheckService.class, "(instance.name=" + consumer.getInstanceName() + ")", 1000);
+ CheckService cs = osgiHelper.getServiceObject(CheckService.class,
+ "(instance.name=" + consumer.getInstanceName()+")");
+ assertNotNull(cs);
+
+ // the exception is caught by the implementation, and false is returned.
+ assertFalse(cs.check());
+
+ // we start the provider.
+ provider.start();
+ assertNotNull(osgiHelper.getServiceObject(FooService.class));
+
+ // This time everything is fine.
+ assertTrue(cs.check());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalDependencies.java
new file mode 100644
index 0000000..5ee0d9d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalDependencies.java
@@ -0,0 +1,498 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+public class TestDelayedOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidOptionalCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefOptionalCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothOptionalCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MapOptionalCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("DictOptionalCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalMultipleDependencies.java
new file mode 100644
index 0000000..bef1f03
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestDelayedOptionalMultipleDependencies.java
@@ -0,0 +1,368 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedOptionalMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleOptionalMultipleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidOptionalMultipleCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectOptionalMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ instance1.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance1.stop();
+ }
+
+ @Test
+ public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 2);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance2.stop();
+ }
+
+ @Test
+ public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 2);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance3.stop();
+ }
+
+ @Test
+ public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 2);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance4.stop();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalDependencies.java
new file mode 100644
index 0000000..32ba068
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalDependencies.java
@@ -0,0 +1,369 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodDelayedOptionalDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefOptionalCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapOptionalCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("MDictOptionalCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalMultipleDependencies.java
new file mode 100644
index 0000000..9c0dcb4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodDelayedOptionalMultipleDependencies.java
@@ -0,0 +1,215 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodDelayedOptionalMultipleDependencies extends Common {
+
+ ComponentInstance instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+
+ @Before
+ public void setUp() {
+ try {
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectOptionalMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", (Boolean) props.get("result")); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 2);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 2);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance4.stop();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalDependencies.java
new file mode 100644
index 0000000..339fd56
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalDependencies.java
@@ -0,0 +1,436 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodOptionalDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothOptionalCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapOptionalCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("MDictOptionalCheckServiceProvider").createComponentInstance(i7);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testObject() {
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalMultipleDependencies.java
new file mode 100644
index 0000000..6cea26e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestMethodOptionalMultipleDependencies.java
@@ -0,0 +1,288 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodOptionalMultipleDependencies extends Common {
+
+ ComponentInstance instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectOptionalMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 2);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 2);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestNullableTransitiveClassloading.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestNullableTransitiveClassloading.java
new file mode 100644
index 0000000..d7989e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestNullableTransitiveClassloading.java
@@ -0,0 +1,41 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.Test;
+
+
+/**
+ * Reproduces FELIX-2093
+ * iPOJO doesn't always use the correct class loader to load nullable object.
+ */
+public class TestNullableTransitiveClassloading extends Common {
+
+
+ @Test
+ public void testCreation() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Factory factory = ipojoHelper.getFactory("optional-log-cons");
+ ComponentInstance ci = factory.createComponentInstance(null);
+ ci.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalDependencies.java
new file mode 100644
index 0000000..37b3e82
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalDependencies.java
@@ -0,0 +1,551 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+ @Before public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name","FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name","Simple");
+ instance1 = ipojoHelper.getFactory("SimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name","Void");
+ instance2 = ipojoHelper.getFactory("VoidOptionalCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name","Object");
+ instance3 = ipojoHelper.getFactory("ObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name","Ref");
+ instance4 = ipojoHelper.getFactory("RefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name","Both");
+ instance5 = ipojoHelper.getFactory("BothOptionalCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name","Map");
+ instance6 = ipojoHelper.getFactory("MapOptionalCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name","Dictionary");
+ instance7 = ipojoHelper.getFactory("DictOptionalCheckServiceProvider").createComponentInstance(i7);
+ } catch(Exception e) { fail(e.getMessage()); }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1 ("+props.get("object")+")", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean)props.get("result")).booleanValue()); // True, a provider is there
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -3 ("+((Integer)props.get("voidU")) + ")", ((Integer)props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 3", props.get("object"));
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 3", ((Double)props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2 (" + ((Integer)props.get("objectB")).intValue() + ")", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue()); // Nullable object.
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer)props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer)props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer)props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer)props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer)props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer)props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -2", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer)props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer)props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -3", ((Integer)props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation -3", ((Integer)props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer)props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer)props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer)props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer)props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer)props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -2", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer)props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer)props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -3", ((Integer)props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalMultipleDependencies.java
new file mode 100644
index 0000000..2a91d56
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalMultipleDependencies.java
@@ -0,0 +1,485 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name","FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name","FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name","Simple");
+ instance1 = ipojoHelper.getFactory("SimpleOptionalMultipleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name","Void");
+ instance2 = ipojoHelper.getFactory("VoidOptionalMultipleCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name","Object");
+ instance3 = ipojoHelper.getFactory("ObjectOptionalMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name","Ref");
+ instance4 = ipojoHelper.getFactory("RefOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+ } catch(Exception e) { fail(e.getMessage()); }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean)props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double)props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long)props.get("long")).longValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 4", ((Integer)props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 4", ((Integer)props.get("voidU")).intValue(), 2);
+ assertEquals("check object bind callback invocation - 4", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long)props.get("long")).longValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 2);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer)props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer)props.get("refU")).intValue(), 2);
+ assertEquals("Check FS invocation (int) - 0", ((Integer)props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long)props.get("long")).longValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalNoNullableDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalNoNullableDependencies.java
new file mode 100644
index 0000000..85067c7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestOptionalNoNullableDependencies.java
@@ -0,0 +1,550 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalNoNullableDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleOptionalNoNullableCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidOptionalNoNullableCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectOptionalNoNullableCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefOptionalNoNullableCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothOptionalNoNullableCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MapOptionalNoNullableCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("DictOptionalNoNullableCheckServiceProvider").createComponentInstance(i7);
+ } catch (Exception e) {
+ e.getMessage();
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ // no service, no nullable => runtime exception expected
+ assertTrue("check excepted exception", ((Boolean) props.get("exception")).booleanValue());
+ assertNull("check CheckService invocation - 1 (" + props.get("result") + ")", props.get("result")); // Null
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1 (" + props.get("object") + ")", props.get("object"));
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is there
+ // No exception expected
+ assertFalse("check unexcepted exception", ((Boolean) props.get("exception")).booleanValue());
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation - 1", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result"));
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -3 (" + ((Integer) props.get("voidU")) + ")", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 3", props.get("object"));
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -1", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2 (" + ((Integer) props.get("objectB")).intValue() + ")", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result")); // No provider.
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -1", props.get("result")); //Null, no provider
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -1", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -1", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -1", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertNull("check CheckService invocation -3", props.get("result")); // Null, no provider
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalDependencies.java
new file mode 100644
index 0000000..b94129b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalDependencies.java
@@ -0,0 +1,498 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+public class TestProxiedDelayedOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidOptionalCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefOptionalCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("ProxiedBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("ProxiedMapOptionalCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("ProxiedDictOptionalCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation - 2", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalMultipleDependencies.java
new file mode 100644
index 0000000..0354a62
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedDelayedOptionalMultipleDependencies.java
@@ -0,0 +1,364 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedDelayedOptionalMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleOptionalMultipleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidOptionalMultipleCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectOptionalMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 2);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 2);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 2);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance4.stop();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedOptionalDependencies.java
new file mode 100644
index 0000000..b656ded
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/optional/TestProxiedOptionalDependencies.java
@@ -0,0 +1,554 @@
+/*
+ * 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.test.dependencies.optional;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidOptionalCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("ProxiedBothOptionalCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("ProxiedMapOptionalCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("ProxiedDictOptionalCheckServiceProvider").createComponentInstance(i7);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1 (" + props.get("object") + ")", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, a provider is there
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -3 (" + ((Integer) props.get("voidU")) + ")", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 3", props.get("object"));
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2 (" + ((Integer) props.get("objectB")).intValue() + ")", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue()); // Nullable object.
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 1);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/pom.xml
new file mode 100644
index 0000000..d1c9706
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-dependency-policies-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..99a99be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
@@ -0,0 +1,65 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if (props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+ public void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
new file mode 100644
index 0000000..6c631f5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+
+ int modified = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+ if (fs != null) {
+ // If nullable = false and proxy, a runtime exception may be launched here
+ // catch the exception and add this to props.
+ try {
+ props.put("exception", Boolean.FALSE); // Set exception to false for checking.
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ } catch (RuntimeException e) {
+ props.put("exception", Boolean.TRUE);
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+
+
+ // Add modified
+ props.put("modified", new Integer(modified));
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ public void voidModify() {
+ modified ++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ protected void objectModify(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! [" + modified + "]");
+ return;
+ }
+ if(o != null && o instanceof FooService) { modified++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void refModify(ServiceReference sr) {
+ if(sr != null) { modified++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ public void bothModify(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { modified++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+
+ protected void propertiesDictionaryModify(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+
+ protected void propertiesMapModify(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
new file mode 100644
index 0000000..db65a4c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+import java.util.*;
+
+public class CollectionCheckService implements CheckService {
+
+ Collection fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
new file mode 100644
index 0000000..4100659
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
new file mode 100644
index 0000000..cccb9be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
@@ -0,0 +1,109 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
new file mode 100644
index 0000000..95cb237
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType2 implements FooService {
+
+ private int m_bar; // Service property.
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static int count = 0;
+
+
+ public boolean foo() {
+ // Update
+ if (m_foo.equals("foo")) {
+ m_foo = "bar";
+ } else {
+ m_foo = "foo";
+ }
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
new file mode 100644
index 0000000..ec7207f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FooServiceDefaultImpl implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 5;
+ }
+
+ public int getInt() {
+ return 5;
+ }
+
+ public long getLong() {
+ return 5;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
new file mode 100644
index 0000000..4bbdeaf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
@@ -0,0 +1,184 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class ListCheckService implements CheckService {
+
+ List fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..2d3a6fa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
@@ -0,0 +1,134 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if(fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+
+ if(fs != null) {
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs = o;
+ }
+ protected void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs = (FooService) context.getService(sr);
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothB++; }
+ fs = o;
+ }
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothU++; }
+ fs = null;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs = null;
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
new file mode 100644
index 0000000..ff8800e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+
+import java.util.*;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB = 0;
+ int mapU = 0;
+ int dictB = 0, dictU=0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) { return null; }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", check());
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapU", mapU);
+ props.put("mapB", mapB);
+ props.put("dictU", dictU);
+ props.put("dictB", dictB);
+ props.put("boolean", getBoolean());
+ props.put("int", getInt());
+ props.put("long", getLong());
+ props.put("double", getDouble());
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs.add(o);
+ }
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs.add(context.getService(sr));
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs.add(o);
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs.remove(o);
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs.add(o);
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs.remove(o);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
new file mode 100644
index 0000000..0e3007d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..63eb7bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int binded;
+
+ public MultipleFilterCheckSubscriber(){
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(binded));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ binded++;
+ }
+ private void Unbind() {
+ binded--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
new file mode 100644
index 0000000..4fd100a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
new file mode 100644
index 0000000..9ac13e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() {
+ return m_grade; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
new file mode 100644
index 0000000..f25a95f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+public class SetCheckService implements CheckService {
+
+ Set fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
new file mode 100644
index 0000000..fe3e00b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
@@ -0,0 +1,159 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+import java.util.Vector;
+
+public class VectorCheckService implements CheckService {
+
+ Vector fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ // simpleB++;
+ }
+
+ public void voidUnbind() {
+ // simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
new file mode 100644
index 0000000..24a14c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ FooService fs2;
+
+ FooService[] fss;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("fs", fs.getInt());
+ props.put("fs2", fs2.getInt());
+
+ int[] grades = new int[fss.length];
+
+ for (int i = 0; i < grades.length; i++) {
+ grades[i] = fss[i].getInt();
+ }
+
+ props.put("fss", grades);
+
+ return props;
+ }
+
+ void bind(FooService svc) {
+ fs2 = svc;
+ }
+
+ void unbind(FooService svc) {
+ fs2 = null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
new file mode 100644
index 0000000..3d09a97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.comparator;
+
+import org.osgi.framework.ServiceReference;
+
+import java.util.Comparator;
+
+public class GradeComparator implements Comparator {
+
+ public int compare(Object arg0, Object arg1) {
+ ServiceReference ref0 = null;
+ ServiceReference ref1 = null;
+ Integer grade0 = null;
+ Integer grade1 = null;
+ if (arg0 instanceof ServiceReference) {
+ ref0 = (ServiceReference) arg0;
+ grade0 = (Integer) ref0.getProperty("grade");
+ }
+ if (arg1 instanceof ServiceReference) {
+ ref1 = (ServiceReference) arg1;
+ grade1 = (Integer) ref1.getProperty("grade");
+ }
+
+ if (ref0 != null && ref1 != null
+ && grade0 != null && grade1 != null) {
+ return grade1.compareTo(grade0); // Best grade first.
+ } else {
+ return 0; // Equals
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
new file mode 100644
index 0000000..0309800
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class GradedFooServiceProvider implements FooService {
+
+
+ private int grade;
+
+ public boolean foo() {
+ return grade > 0;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return grade;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
new file mode 100644
index 0000000..91c33e7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
@@ -0,0 +1,90 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckProvider implements CheckService, FooService {
+
+ private String m_toto;
+
+ private int bind;
+
+ private int unbind;
+
+ public FilterCheckProvider() {
+ m_toto = "A";
+ }
+
+ public boolean check() {
+ if (m_toto.equals("A")) {
+ m_toto = "B";
+ return true;
+ } else {
+ m_toto = "A";
+ return false;
+ }
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bind - unbind));
+ return null;
+ }
+
+ private void Bind() {
+ bind++;
+ }
+
+ private void Unbind() {
+ unbind++;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
new file mode 100644
index 0000000..5ffa4bd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components.filter;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckSubscriber implements CheckService {
+
+ private FooService m_foo;
+
+ private int bound;
+
+ public FilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ m_foo.foo();
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Nullable", new Boolean(m_foo instanceof Nullable));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..0ee898c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int bound;
+
+ public MultipleFilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
new file mode 100644
index 0000000..646bfbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C1 implements Call {
+
+ public String callMe() {
+ return "called";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
new file mode 100644
index 0000000..b4c0c88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C2 {
+
+ private Call c1;
+
+ public String authenticate() {
+ return c1.callMe();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
new file mode 100644
index 0000000..7f71de4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.components.inner;
+
+public class C3 {
+
+ private C2 c2;
+
+ public MyFilter getFilter() {
+ return new MyFilter() {
+ public String authenticate() {
+ System.out.println("My Filter ...");
+ String r = c2.authenticate();
+ System.out.println(" ... " + r);
+ return r;
+ }
+ };
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
new file mode 100644
index 0000000..e3e64cd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components.inner;
+
+public interface MyFilter {
+
+ public String authenticate();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
new file mode 100644
index 0000000..398d342
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components.optional;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.service.log.LogService;
+
+
+@Component(immediate=true, name="optional-log-cons")
+public class MyComponent {
+
+ @Requires(optional=true, proxy=false)
+ private LogService log;
+
+
+ public MyComponent() {
+ System.out.println("Created ! : " + (log instanceof Nullable) + " - " + log);
+ log.log(LogService.LOG_INFO, "Created !");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
new file mode 100644
index 0000000..a89dd43
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
new file mode 100644
index 0000000..f55cfcc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
@@ -0,0 +1,91 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
new file mode 100644
index 0000000..93c3737
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..5b13c7b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ if (fs != null) {
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs = o;
+ }
+
+ protected void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs = (FooService) context.getService(sr);
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ fs = o;
+ }
+
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothU++;
+ }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
new file mode 100644
index 0000000..05481af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs.add(o);
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs.add(context.getService(sr));
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
new file mode 100644
index 0000000..f437e09
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
new file mode 100644
index 0000000..e2f9bc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return m_grade;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
new file mode 100644
index 0000000..14c69c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceDelegator implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceDelegator(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
new file mode 100644
index 0000000..ebc94c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceGetAndDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceGetAndDelegate(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ fs.foo();
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ fs.getBoolean();
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
new file mode 100644
index 0000000..6db5841
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceNoDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ private BundleContext context;
+
+ public CheckServiceNoDelegate(BundleContext bc) {
+ context = bc;
+ helper = new Helper(context, fs);
+ }
+
+ public void start() {
+ helper.publish();
+ }
+
+ public void stop() {
+ helper.unpublish();
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
new file mode 100644
index 0000000..5c04dac
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+
+import java.util.AbstractMap;
+import java.util.Properties;
+
+public class CheckServiceUsingStringService implements CheckService {
+
+ private String string;
+ private AbstractMap map;
+
+
+ public CheckServiceUsingStringService() {
+ System.out.println("Service : " + string);
+ System.out.println("Map : " + map);
+ }
+
+ public boolean check() {
+ return string != null
+ && map != null;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
new file mode 100644
index 0000000..dd86961
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+public class Helper implements CheckService {
+
+
+ private FooService fs;
+ private BundleContext context;
+ private ServiceRegistration reg;
+
+ public Helper(BundleContext bc, FooService svc) {
+ fs = svc;
+ context = bc;
+ }
+
+ public void publish() {
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_PID, "Helper");
+ context.registerService(CheckService.class, this, props);
+ reg = context.registerService(CheckService.class.getName(), this, props);
+ }
+
+ public void unpublish() {
+ if (reg != null) {
+ reg.unregister();
+ }
+ reg = null;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ fs.getBoolean();
+ props.put("helper.fs", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
new file mode 100644
index 0000000..3f4e34c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
@@ -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.felix.ipojo.runtime.core.test.services;
+
+public interface Call {
+
+
+ public String callMe();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..e4366ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..9b8e12b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-comparator.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-comparator.xml
new file mode 100644
index 0000000..1fb7e18
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-comparator.xml
@@ -0,0 +1,55 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradedFooServiceProvider"
+ name="COMPARATOR-gradedFooProvider">
+ <provides>
+ <property field="grade"/>
+ </provides>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicCheckService">
+ <provides/>
+ <requires field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicPriorityCheckService">
+ <provides/>
+ <requires policy="dynamic-priority" field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-filter.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-filter.xml
new file mode 100644
index 0000000..975b5b5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-filter.xml
@@ -0,0 +1,141 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <!-- Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimpleFilterCheckServiceProvider" architecture="true">
+ <provides>
+ <property field="m_toto" name="toto" value="A" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFromCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" from="A" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimplePIDCheckServiceProvider" architecture="true">
+ <provides>
+ <property type="String" name="service.pid" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1"
+ optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate filter Dependencies-->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Aggregate Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false"
+ optional="true">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-policies.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-policies.xml
new file mode 100644
index 0000000..852763f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata-policies.xml
@@ -0,0 +1,283 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Static Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Static Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <!-- Static Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticSimpleMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticVoidMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMRefMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Dynamic-Priority -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.RankedFooProviderType1"
+ name="RankedFooProviderType" architecture="true">
+ <provides>
+ <property field="m_grade" name="service.ranking"/>
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata.xml
new file mode 100644
index 0000000..e42a2eb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/main/resources/metadata.xml
@@ -0,0 +1,1083 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<!--
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType1"
+ name="FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Simple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" proxy="true"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <!-- Simple & Optional Dependencies with default-implementation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DISimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="BothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedBothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="MapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedMapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="DictMultipleCheckServiceProvider" architecture="true" >
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedDictMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefMultipleCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MBothMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MMapMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MDictMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as List -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="SimpleListCheckServiceProvider" architecture="true">
+ <requires proxy="false"
+ field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="OptionalListCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false"
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedSimpleListCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedOptionalListCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Vector -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="SimpleVectorCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind"/>
+ <callback type="unbind" method="objectUnbind"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="OptionalVectorCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Set -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="SimpleSetCheckServiceProvider" architecture="true">
+ <requires proxy="false" field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="OptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedSimpleSetCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedOptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Collection -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="SimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedSimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="OptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedOptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+
+
+ <!-- Modify method test -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType2"
+ name="FooProviderType-Updatable" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" value="foo"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ <callback type="modified" method="voidModify"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ <callback type="modified" method="objectModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ <callback type="modified" method="refModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ <callback type="modified" method="bothModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ <callback type="modified" method="propertiesMapModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ <callback type="modified" method="propertiesDictionaryModify" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Proxy Tests -->
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceGetAndDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceNoDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceUsingStringService"
+ immediate="true">
+ <provides/>
+ <requires field="string"/>
+ <requires field="map"/>
+ </component>
+
+ <!-- Inner + Proxy mix -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C1">
+ <provides/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C2">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C2"/>
+ <requires field="c1"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C3">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C3"/>
+ <requires field="c2"/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
new file mode 100644
index 0000000..4fe2436
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.dependencies;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ eventadmin()
+ };
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.test.components.inner"
+ );
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ // Use an old version of the event admin to avoid import package issues on KF
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.2.10"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin",
+ "1.8.0").versionAsInProject());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/comparator/TestComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/comparator/TestComparator.java
new file mode 100644
index 0000000..d393c48
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/comparator/TestComparator.java
@@ -0,0 +1,159 @@
+/*
+ * 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.test.dependencies.comparator;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestComparator extends Common {
+
+ String gradeFactory = "COMPARATOR-gradedFooProvider";
+ String dynamic = "COMPARATOR-DynamicCheckService";
+ String dynamicpriority = "COMPARATOR-DynamicPriorityCheckService";
+
+
+ ComponentInstance dynInstance;
+ ComponentInstance dpInstance;
+
+ @Before
+ public void setUp() {
+ dynInstance = ipojoHelper.createComponentInstance(dynamic, (Properties) null);
+ dpInstance = ipojoHelper.createComponentInstance(dynamicpriority, (Properties) null);
+ }
+
+ @After
+ public void tearDown() {
+ ipojoHelper.dispose();
+ }
+
+ @Test
+ public void testDynamic() {
+ createGrade(1);
+ ComponentInstance grade2 = createGrade(2);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), dynInstance.getInstanceName());
+ assertNotNull("CS availability", ref);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties result = cs.getProps();
+ int fsGrade = (Integer) result.get("fs");
+ int fs2Grade = (Integer) result.get("fs2");
+ int[] fssGrades = (int[]) result.get("fss");
+
+ // We should have been injected with the highest one.
+ assertEquals("fs grade -1", 2, fsGrade);
+ assertEquals("fs2 grade -1", 2, fs2Grade);
+ assertEquals("fss grade size -1", 2, fssGrades.length);
+
+
+ assertEquals("fss grade[0] -1", 2, fssGrades[0]);
+ assertEquals("fss grade[1] -1", 1, fssGrades[1]);
+
+ createGrade(3);
+ result = cs.getProps();
+ fsGrade = ((Integer) result.get("fs")).intValue();
+ fs2Grade = ((Integer) result.get("fs2")).intValue();
+ fssGrades = (int[]) result.get("fss");
+
+ assertEquals("fs grade -2", 2, fsGrade);
+ assertEquals("fs2 grade -2", 2, fs2Grade);
+ assertEquals("fss grade size -2", 3, fssGrades.length);
+ assertEquals("fss grade[0] -2", 2, fssGrades[0]);
+ assertEquals("fss grade[1] -2", 1, fssGrades[1]);
+ assertEquals("fss grade[2] -2", 3, fssGrades[2]);
+
+ grade2.stop();
+
+ result = cs.getProps();
+ fsGrade = ((Integer) result.get("fs")).intValue();
+ fs2Grade = ((Integer) result.get("fs2")).intValue();
+ fssGrades = (int[]) result.get("fss");
+
+ assertEquals("fs grade -3", 3, fsGrade);
+ assertEquals("fs2 grade -3", 3, fs2Grade);
+ assertEquals("fss grade size -3", 2, fssGrades.length);
+ assertEquals("fss grade[0] -3", 1, fssGrades[0]);
+ assertEquals("fss grade[1] -3", 3, fssGrades[1]);
+ }
+
+ @Test
+ public void testDynamicPriority() {
+ createGrade(1);
+ ComponentInstance grade2 = createGrade(2);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), dpInstance.getInstanceName());
+ assertNotNull("CS availability", ref);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+ Properties result = cs.getProps();
+ int fsGrade = (Integer) result.get("fs");
+ int fs2Grade = (Integer) result.get("fs2");
+ int[] fssGrades = (int[]) result.get("fss");
+
+ assertEquals("fs grade -1", 2, fsGrade);
+ assertEquals("fs2 grade -1", 2, fs2Grade);
+ assertEquals("fss grade size -1", 2, fssGrades.length);
+ assertEquals("fss grade[0] -1", 2, fssGrades[0]);
+ assertEquals("fss grade[1] -1", 1, fssGrades[1]);
+
+ createGrade(3);
+ result = cs.getProps();
+ fsGrade = ((Integer) result.get("fs")).intValue();
+ fs2Grade = ((Integer) result.get("fs2")).intValue();
+ fssGrades = (int[]) result.get("fss");
+
+ assertEquals("fs grade -2", 3, fsGrade);
+ assertEquals("fs2 grade -2", 3, fs2Grade);
+ assertEquals("fss grade size -2", 3, fssGrades.length);
+ assertEquals("fss grade[0] -2", 3, fssGrades[0]);
+ assertEquals("fss grade[1] -2", 2, fssGrades[1]);
+ assertEquals("fss grade[2] -2", 1, fssGrades[2]);
+
+ grade2.stop();
+
+ result = cs.getProps();
+ fsGrade = ((Integer) result.get("fs")).intValue();
+ fs2Grade = ((Integer) result.get("fs2")).intValue();
+ fssGrades = (int[]) result.get("fss");
+
+ assertEquals("fs grade -3", 3, fsGrade);
+ assertEquals("fs2 grade -3", 3, fs2Grade);
+ assertEquals("fss grade size -3", 2, fssGrades.length);
+ assertEquals("fss grade[0] -3", 3, fssGrades[0]);
+ assertEquals("fss grade[1] -3", 1, fssGrades[1]);
+ }
+
+ private ComponentInstance createGrade(int grade) {
+ Properties props = new Properties();
+ props.put("grade", grade);
+ return ipojoHelper.createComponentInstance(gradeFactory, props);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestDynamicPriority.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestDynamicPriority.java
new file mode 100644
index 0000000..e5b9d49
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestDynamicPriority.java
@@ -0,0 +1,165 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestDynamicPriority extends Common {
+
+ ComponentInstance instance1, instance3;
+ ComponentInstance fooProvider;
+ ComponentInstance fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider-1");
+ prov.put("service.ranking", "1");
+ fooProvider = ipojoHelper.getFactory("RankedFooProviderType").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider-2");
+ prov2.put("service.ranking", "0");
+ fooProvider2 = ipojoHelper.getFactory("RankedFooProviderType").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("DPSimpleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("DPObjectCheckServiceProvider").createComponentInstance(i3);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance3.dispose();
+ fooProvider.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance3 = null;
+ fooProvider = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // Check grade
+ Integer grade = (Integer) cs.getProps().get("int");
+ assertEquals("Check first grade", 1, grade.intValue());
+
+ fooProvider.stop(); // Turn off the best provider.
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // Check grade
+ grade = (Integer) cs.getProps().get("int");
+ assertEquals("Check second grade", 0, grade.intValue());
+
+ fooProvider.start(); // Turn on the best provider.
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // Check grade
+ grade = (Integer) cs.getProps().get("int");
+ assertEquals("Check third grade", 1, grade.intValue());
+
+
+ // Increase the second provider grade.
+ ServiceReference fs_ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check foo service (2) reference", fs_ref);
+ FooService fs = (FooService) getContext().getService(fs_ref);
+
+ fs.foo(); // Increase the grade (now = 2)
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // Check grade
+ grade = (Integer) cs.getProps().get("int");
+ assertEquals("Check fourth grade", 2, grade.intValue());
+
+ // Increase the other provider grade.
+ fs_ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ assertNotNull("Check foo service (1) reference", fs_ref);
+ fs = (FooService) getContext().getService(fs_ref);
+ fs.foo(); //(grade = 3)
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // Check grade
+ grade = (Integer) cs.getProps().get("int");
+ assertEquals("Check fifth grade", 3, grade.intValue());
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(fs_ref);
+ fooProvider.stop();
+ fooProvider2.stop();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodOptionalDependencies.java
new file mode 100644
index 0000000..461f772
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodOptionalDependencies.java
@@ -0,0 +1,275 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestStaticMethodOptionalDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5;
+
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("StaticMObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("StaticMRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("StaticMBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testObject() {
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodSimpleDependencies.java
new file mode 100644
index 0000000..10421a7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMethodSimpleDependencies.java
@@ -0,0 +1,198 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestStaticMethodSimpleDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("StaticMObjectCheckServiceProvider").createComponentInstance(i3);
+ assertNotNull("check instance 3", instance3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("StaticMRefCheckServiceProvider").createComponentInstance(i4);
+ assertNotNull("check instance 4", instance4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("StaticMBothCheckServiceProvider").createComponentInstance(i5);
+ assertNotNull("check instance 5", instance5);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+
+ @Test
+ public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMultipleDependencies.java
new file mode 100644
index 0000000..6f9a1e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticMultipleDependencies.java
@@ -0,0 +1,325 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestStaticMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("StaticSimpleMultipleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("StaticVoidMultipleCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("StaticObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("StaticRefMultipleCheckServiceProvider").createComponentInstance(i4);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testSimple() {
+ instance1.stop();
+ fooProvider1.start();
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+ // instance is stopped and then restarted, so bound to fooprovider 2.
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testVoid() {
+ instance2.stop();
+ fooProvider1.start();
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testObject() {
+ instance3.stop();
+ fooProvider1.start();
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ // Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ // Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+ // Instance stopped and then restarted, bound to foo provider 2.
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testRef() {
+ instance4.stop();
+ fooProvider1.start();
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+ // Stop and then restarted, bound to foo provider 2.
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticOptionalDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticOptionalDependencies.java
new file mode 100644
index 0000000..fd03bf9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticOptionalDependencies.java
@@ -0,0 +1,521 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestStaticOptionalDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("StaticSimpleOptionalCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("StaticVoidOptionalCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("StaticObjectOptionalCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("StaticRefOptionalCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("StaticBothOptionalCheckServiceProvider").createComponentInstance(i5);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 0);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+
+ //Check properties
+ assertFalse("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // False, the provider was not bound
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testDelayedSimple() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ instance1.stop();
+ fooProvider.start();
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, the provider was bound
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+
+ fooProvider.stop();
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID); // Dependency broken,re started with no service.
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 1", props.get("object"));
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 0);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3 (" + ((Integer) props.get("voidU")) + ")", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertNull("Check FS invocation (object) - 3", props.get("object"));
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testDelayedVoid() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ instance2.stop();
+ fooProvider.start();
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, the provider was bound
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+
+ fooProvider.stop();
+ // The instance is restarted.
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3 (" + id.getState() + ")", id.getState() == ComponentInstance.VALID); // Dependency broken and then (no service injected) restarted
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2 (" + ((Integer) props.get("objectB")).intValue() + ")", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testDelayedObject() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ instance3.stop();
+ fooProvider.start();
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, the provider was bound
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertNotNull("Check FS invocation (object) - 2", props.get("object"));
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID); // Dependency broken and restarted with no service
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ public void atestRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ public void atestBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue()); // False is returned (nullable)
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -2", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -2", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3 (" + id.getState() + ")", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) getContext().getService(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation -3", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -3", ((Integer) props.get("bothU")).intValue(), 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticSimpleDependencies.java
new file mode 100644
index 0000000..9ce4d9e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-policies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/policies/TestStaticSimpleDependencies.java
@@ -0,0 +1,351 @@
+/*
+ * 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.test.dependencies.policies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestStaticSimpleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("StaticSimpleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("StaticVoidCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("StaticObjectCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("StaticRefCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("StaticBothCheckServiceProvider").createComponentInstance(i5);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider = null;
+ }
+
+ @Test
+ public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+ // instance1 has to be stopped and restarted.
+
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID); // The instance was invalidated and revalidated.
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ Object o = getContext().getService(cs_ref);
+ CheckService cs = (CheckService) o;
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1 (" + ((Integer) props.get("voidB")).intValue() + ")", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID); // The instance was revalidated.
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability - 2", cs_ref);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability - 2", cs_ref);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability - 2", cs_ref);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability - 2", cs_ref);
+
+ fooProvider.stop();
+
+ arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/pom.xml
new file mode 100644
index 0000000..f506bfa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-dependency-proxies-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..99a99be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
@@ -0,0 +1,65 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if (props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+ public void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
new file mode 100644
index 0000000..6c631f5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+
+ int modified = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+ if (fs != null) {
+ // If nullable = false and proxy, a runtime exception may be launched here
+ // catch the exception and add this to props.
+ try {
+ props.put("exception", Boolean.FALSE); // Set exception to false for checking.
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ } catch (RuntimeException e) {
+ props.put("exception", Boolean.TRUE);
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+
+
+ // Add modified
+ props.put("modified", new Integer(modified));
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ public void voidModify() {
+ modified ++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ protected void objectModify(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! [" + modified + "]");
+ return;
+ }
+ if(o != null && o instanceof FooService) { modified++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void refModify(ServiceReference sr) {
+ if(sr != null) { modified++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ public void bothModify(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { modified++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+
+ protected void propertiesDictionaryModify(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+
+ protected void propertiesMapModify(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
new file mode 100644
index 0000000..db65a4c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+import java.util.*;
+
+public class CollectionCheckService implements CheckService {
+
+ Collection fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
new file mode 100644
index 0000000..4100659
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
new file mode 100644
index 0000000..cccb9be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
@@ -0,0 +1,109 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
new file mode 100644
index 0000000..95cb237
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType2 implements FooService {
+
+ private int m_bar; // Service property.
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static int count = 0;
+
+
+ public boolean foo() {
+ // Update
+ if (m_foo.equals("foo")) {
+ m_foo = "bar";
+ } else {
+ m_foo = "foo";
+ }
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
new file mode 100644
index 0000000..ec7207f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FooServiceDefaultImpl implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 5;
+ }
+
+ public int getInt() {
+ return 5;
+ }
+
+ public long getLong() {
+ return 5;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
new file mode 100644
index 0000000..4bbdeaf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
@@ -0,0 +1,184 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class ListCheckService implements CheckService {
+
+ List fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..2d3a6fa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
@@ -0,0 +1,134 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if(fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+
+ if(fs != null) {
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs = o;
+ }
+ protected void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs = (FooService) context.getService(sr);
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothB++; }
+ fs = o;
+ }
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothU++; }
+ fs = null;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs = null;
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
new file mode 100644
index 0000000..ff8800e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+
+import java.util.*;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB = 0;
+ int mapU = 0;
+ int dictB = 0, dictU=0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) { return null; }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", check());
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapU", mapU);
+ props.put("mapB", mapB);
+ props.put("dictU", dictU);
+ props.put("dictB", dictB);
+ props.put("boolean", getBoolean());
+ props.put("int", getInt());
+ props.put("long", getLong());
+ props.put("double", getDouble());
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs.add(o);
+ }
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs.add(context.getService(sr));
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs.add(o);
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs.remove(o);
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs.add(o);
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs.remove(o);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
new file mode 100644
index 0000000..0e3007d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..63eb7bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int binded;
+
+ public MultipleFilterCheckSubscriber(){
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(binded));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ binded++;
+ }
+ private void Unbind() {
+ binded--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
new file mode 100644
index 0000000..4fd100a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
new file mode 100644
index 0000000..9ac13e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() {
+ return m_grade; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
new file mode 100644
index 0000000..f25a95f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+public class SetCheckService implements CheckService {
+
+ Set fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
new file mode 100644
index 0000000..fe3e00b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
@@ -0,0 +1,159 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+import java.util.Vector;
+
+public class VectorCheckService implements CheckService {
+
+ Vector fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ // simpleB++;
+ }
+
+ public void voidUnbind() {
+ // simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
new file mode 100644
index 0000000..5295912
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ FooService fs2;
+
+ FooService[] fss;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("fs", new Integer(fs.getInt()));
+ props.put("fs2", new Integer(fs2.getInt()));
+
+ int[] grades = new int[fss.length];
+
+ for (int i = 0; i < grades.length; i++) {
+ grades[i] = fss[i].getInt();
+ }
+
+ props.put("fss", grades);
+
+ return props;
+ }
+
+ void bind(FooService svc) {
+ fs2 = svc;
+ }
+
+ void unbind(FooService svc) {
+ fs2 = null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
new file mode 100644
index 0000000..3d09a97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.comparator;
+
+import org.osgi.framework.ServiceReference;
+
+import java.util.Comparator;
+
+public class GradeComparator implements Comparator {
+
+ public int compare(Object arg0, Object arg1) {
+ ServiceReference ref0 = null;
+ ServiceReference ref1 = null;
+ Integer grade0 = null;
+ Integer grade1 = null;
+ if (arg0 instanceof ServiceReference) {
+ ref0 = (ServiceReference) arg0;
+ grade0 = (Integer) ref0.getProperty("grade");
+ }
+ if (arg1 instanceof ServiceReference) {
+ ref1 = (ServiceReference) arg1;
+ grade1 = (Integer) ref1.getProperty("grade");
+ }
+
+ if (ref0 != null && ref1 != null
+ && grade0 != null && grade1 != null) {
+ return grade1.compareTo(grade0); // Best grade first.
+ } else {
+ return 0; // Equals
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
new file mode 100644
index 0000000..0309800
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class GradedFooServiceProvider implements FooService {
+
+
+ private int grade;
+
+ public boolean foo() {
+ return grade > 0;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return grade;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
new file mode 100644
index 0000000..91c33e7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
@@ -0,0 +1,90 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckProvider implements CheckService, FooService {
+
+ private String m_toto;
+
+ private int bind;
+
+ private int unbind;
+
+ public FilterCheckProvider() {
+ m_toto = "A";
+ }
+
+ public boolean check() {
+ if (m_toto.equals("A")) {
+ m_toto = "B";
+ return true;
+ } else {
+ m_toto = "A";
+ return false;
+ }
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bind - unbind));
+ return null;
+ }
+
+ private void Bind() {
+ bind++;
+ }
+
+ private void Unbind() {
+ unbind++;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
new file mode 100644
index 0000000..5ffa4bd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components.filter;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckSubscriber implements CheckService {
+
+ private FooService m_foo;
+
+ private int bound;
+
+ public FilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ m_foo.foo();
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Nullable", new Boolean(m_foo instanceof Nullable));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..0ee898c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int bound;
+
+ public MultipleFilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
new file mode 100644
index 0000000..646bfbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C1 implements Call {
+
+ public String callMe() {
+ return "called";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
new file mode 100644
index 0000000..b4c0c88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C2 {
+
+ private Call c1;
+
+ public String authenticate() {
+ return c1.callMe();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
new file mode 100644
index 0000000..7f71de4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.components.inner;
+
+public class C3 {
+
+ private C2 c2;
+
+ public MyFilter getFilter() {
+ return new MyFilter() {
+ public String authenticate() {
+ System.out.println("My Filter ...");
+ String r = c2.authenticate();
+ System.out.println(" ... " + r);
+ return r;
+ }
+ };
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
new file mode 100644
index 0000000..e3e64cd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components.inner;
+
+public interface MyFilter {
+
+ public String authenticate();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
new file mode 100644
index 0000000..398d342
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components.optional;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.service.log.LogService;
+
+
+@Component(immediate=true, name="optional-log-cons")
+public class MyComponent {
+
+ @Requires(optional=true, proxy=false)
+ private LogService log;
+
+
+ public MyComponent() {
+ System.out.println("Created ! : " + (log instanceof Nullable) + " - " + log);
+ log.log(LogService.LOG_INFO, "Created !");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
new file mode 100644
index 0000000..a89dd43
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
new file mode 100644
index 0000000..f55cfcc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
@@ -0,0 +1,91 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
new file mode 100644
index 0000000..93c3737
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..5b13c7b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ if (fs != null) {
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs = o;
+ }
+
+ protected void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs = (FooService) context.getService(sr);
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ fs = o;
+ }
+
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothU++;
+ }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
new file mode 100644
index 0000000..05481af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs.add(o);
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs.add(context.getService(sr));
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
new file mode 100644
index 0000000..f437e09
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
new file mode 100644
index 0000000..e2f9bc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return m_grade;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
new file mode 100644
index 0000000..14c69c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceDelegator implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceDelegator(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
new file mode 100644
index 0000000..ebc94c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceGetAndDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceGetAndDelegate(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ fs.foo();
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ fs.getBoolean();
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
new file mode 100644
index 0000000..6db5841
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceNoDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ private BundleContext context;
+
+ public CheckServiceNoDelegate(BundleContext bc) {
+ context = bc;
+ helper = new Helper(context, fs);
+ }
+
+ public void start() {
+ helper.publish();
+ }
+
+ public void stop() {
+ helper.unpublish();
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
new file mode 100644
index 0000000..5c04dac
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+
+import java.util.AbstractMap;
+import java.util.Properties;
+
+public class CheckServiceUsingStringService implements CheckService {
+
+ private String string;
+ private AbstractMap map;
+
+
+ public CheckServiceUsingStringService() {
+ System.out.println("Service : " + string);
+ System.out.println("Map : " + map);
+ }
+
+ public boolean check() {
+ return string != null
+ && map != null;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
new file mode 100644
index 0000000..5759990
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+public class Helper implements CheckService {
+
+
+ private FooService fs;
+ private BundleContext context;
+ private ServiceRegistration reg;
+
+ public Helper(BundleContext bc, FooService svc) {
+ fs = svc;
+ context = bc;
+ }
+
+ public void publish() {
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_PID, "Helper");
+ reg = context.registerService(CheckService.class.getName(), this, props);
+ }
+
+ public void unpublish() {
+ if (reg != null) {
+ reg.unregister();
+ }
+ reg = null;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ fs.getBoolean();
+ props.put("helper.fs", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
new file mode 100644
index 0000000..3f4e34c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
@@ -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.felix.ipojo.runtime.core.test.services;
+
+public interface Call {
+
+
+ public String callMe();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..e4366ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..9b8e12b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-comparator.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-comparator.xml
new file mode 100644
index 0000000..1fb7e18
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-comparator.xml
@@ -0,0 +1,55 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradedFooServiceProvider"
+ name="COMPARATOR-gradedFooProvider">
+ <provides>
+ <property field="grade"/>
+ </provides>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicCheckService">
+ <provides/>
+ <requires field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicPriorityCheckService">
+ <provides/>
+ <requires policy="dynamic-priority" field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-filter.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-filter.xml
new file mode 100644
index 0000000..975b5b5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-filter.xml
@@ -0,0 +1,141 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <!-- Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimpleFilterCheckServiceProvider" architecture="true">
+ <provides>
+ <property field="m_toto" name="toto" value="A" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFromCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" from="A" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimplePIDCheckServiceProvider" architecture="true">
+ <provides>
+ <property type="String" name="service.pid" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1"
+ optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate filter Dependencies-->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Aggregate Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false"
+ optional="true">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-policies.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-policies.xml
new file mode 100644
index 0000000..852763f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata-policies.xml
@@ -0,0 +1,283 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Static Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothCheckServiceProvider" architecture="true">
+ <requires policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Static Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticSimpleOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticVoidOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.CheckServiceProvider"
+ name="StaticBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMObjectOptionalCheckServiceProvider"
+ architecture="true">
+ <requires optional="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMRefOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodCheckServiceProvider"
+ name="StaticMBothOptionalCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <!-- Static Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticSimpleMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticVoidMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MultipleCheckService"
+ name="StaticBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMObjectMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMRefMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" policy="static">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.MethodMultipleCheckService"
+ name="StaticMBothMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" policy="static">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Dynamic-Priority -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.RankedFooProviderType1"
+ name="RankedFooProviderType" architecture="true">
+ <provides>
+ <property field="m_grade" name="service.ranking"/>
+ </provides>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.policies.DynCheckServiceProvider"
+ name="DPObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" policy="dynamic-priority">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata.xml
new file mode 100644
index 0000000..e42a2eb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/main/resources/metadata.xml
@@ -0,0 +1,1083 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<!--
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType1"
+ name="FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Simple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" proxy="true"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Simple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictOptionalNoNullableCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" nullable="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <!-- Simple & Optional Dependencies with default-implementation -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DISimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIVoidOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIObjectOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIRefOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIBothOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIMapOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DIDictOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMObjectOptionalCheckServiceProvider" architecture="true">
+ <requires optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMRefOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMBothOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMMapOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="DIMDictOptionalCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.core.test.components.FooServiceDefaultImpl">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="BothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedBothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="MapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedMapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="DictMultipleCheckServiceProvider" architecture="true" >
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedDictMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefMultipleCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MBothMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MMapMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MDictMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple & Optional Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedSimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedVoidOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ProxiedRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires aggregate="true" optional="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true" optional="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as List -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="SimpleListCheckServiceProvider" architecture="true">
+ <requires proxy="false"
+ field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="OptionalListCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false"
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedSimpleListCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="ProxiedOptionalListCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Vector -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="SimpleVectorCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind"/>
+ <callback type="unbind" method="objectUnbind"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="OptionalVectorCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Set -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="SimpleSetCheckServiceProvider" architecture="true">
+ <requires proxy="false" field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="OptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedSimpleSetCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="ProxiedOptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Collection -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="SimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedSimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="OptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="ProxiedOptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+
+
+ <!-- Modify method test -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType2"
+ name="FooProviderType-Updatable" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" value="foo"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ <callback type="modified" method="voidModify"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ <callback type="modified" method="objectModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ <callback type="modified" method="refModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ <callback type="modified" method="bothModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ <callback type="modified" method="propertiesMapModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ <callback type="modified" method="propertiesDictionaryModify" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Proxy Tests -->
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceGetAndDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceNoDelegate">
+ <provides/>
+ <requires field="fs" optional="true"/>
+ <callback transition="validate" method="start"/>
+ <callback transition="invalidate" method="stop"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceUsingStringService"
+ immediate="true">
+ <provides/>
+ <requires field="string"/>
+ <requires field="map"/>
+ </component>
+
+ <!-- Inner + Proxy mix -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C1">
+ <provides/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C2">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C2"/>
+ <requires field="c1"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C3">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C3"/>
+ <requires field="c2"/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
new file mode 100644
index 0000000..67029d0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.dependencies;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[]{
+ eventadmin()
+ };
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.test.components.inner"
+ );
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ // Use an old version of the event admin to avoid import package issues on KF
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.2.10"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin",
+ "1.8.0").versionAsInProject());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedCollectionMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedCollectionMultipleDependencies.java
new file mode 100644
index 0000000..1e87c0f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedCollectionMultipleDependencies.java
@@ -0,0 +1,256 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedCollectionMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleCollectionCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("ProxiedOptionalCollectionCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedMultipleDependencies.java
new file mode 100644
index 0000000..ab46719
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedMultipleDependencies.java
@@ -0,0 +1,525 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedDelayedMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleMultipleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidMultipleCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("ProxiedBothMultipleCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("ProxiedMapMultipleCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("ProxiedDictMultipleCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance4.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance5.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance6.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance7.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedSimpleDependencies.java
new file mode 100644
index 0000000..e35130d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedDelayedSimpleDependencies.java
@@ -0,0 +1,374 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedDelayedSimpleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("ProxiedBothCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("ProxiedMapCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("ProxiedDictCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+ fooProvider.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+ fooProvider.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+ fooProvider.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedListMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedListMultipleDependencies.java
new file mode 100644
index 0000000..60876d7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedListMultipleDependencies.java
@@ -0,0 +1,256 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedListMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleListCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("ProxiedOptionalListCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSetMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSetMultipleDependencies.java
new file mode 100644
index 0000000..2e67bad
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSetMultipleDependencies.java
@@ -0,0 +1,256 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedSetMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleSetCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("ProxiedOptionalSetCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSimpleDependencies.java
new file mode 100644
index 0000000..5559a91
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxiedSimpleDependencies.java
@@ -0,0 +1,418 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxiedSimpleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7, instance8;
+ ComponentInstance fooProvider;
+
+ @Before public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name","FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name","Simple");
+ instance1 = ipojoHelper.getFactory("ProxiedSimpleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name","Void");
+ instance2 = ipojoHelper.getFactory("ProxiedVoidCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name","Object");
+ instance3 = ipojoHelper.getFactory("ProxiedObjectCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name","Ref");
+ instance4 = ipojoHelper.getFactory("ProxiedRefCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name","Both");
+ instance5 = ipojoHelper.getFactory("ProxiedBothCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name","Double");
+ instance6 = ipojoHelper.getFactory("ProxiedDoubleCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name","Map");
+ instance7 = ipojoHelper.getFactory("ProxiedMapCheckServiceProvider").createComponentInstance(i7);
+
+ Properties i8 = new Properties();
+ i8.put("instance.name","Dictionary");
+ instance8 = ipojoHelper.getFactory("ProxiedDictCheckServiceProvider").createComponentInstance(i8);
+ } catch(Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage()); }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ instance8.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ instance8 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ Object o = osgiHelper.getRawServiceObject(cs_ref);
+ CheckService cs = (CheckService) o;
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1 ("+((Integer)props.get("voidB")).intValue()+")", ((Integer)props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDouble() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertNotNull("Check cs", cs);
+ cs.check();
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer)props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer)props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean)props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer)props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer)props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer)props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer)props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer)props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer)props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxyTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxyTest.java
new file mode 100644
index 0000000..a19eae5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-proxies/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/proxies/TestProxyTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.test.dependencies.proxies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestProxyTest extends Common {
+
+
+ @Test
+ public void testDelegation() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1-Proxy");
+ ComponentInstance fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator").createComponentInstance(i1);
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertTrue(helper.toString().contains("$$Proxy")); // This is the suffix.
+
+ assertTrue(cs.check());
+
+ fooProvider1.dispose();
+ instance1.dispose();
+ }
+
+ @Test
+ public void testDelegationOnNullable() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "DelegatorNullable");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator").createComponentInstance(i1);
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertTrue(helper.toString().contains("$$Proxy")); // This is the suffix.
+
+ assertFalse(cs.check()); // Nullable.
+
+ instance1.dispose();
+ }
+
+
+ @Test
+ public void testGetAndDelegation() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1-Proxy");
+ ComponentInstance fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceGetAndDelegate").createComponentInstance(i1);
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertTrue(helper.toString().contains("$$Proxy")); // This is the suffix.
+
+
+ assertTrue(cs.check());
+
+ fooProvider1.dispose();
+ instance1.dispose();
+ }
+
+ @Test
+ public void testGetAndDelegationOnNullable() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "DelegatorNullable");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceGetAndDelegate").createComponentInstance(i1);
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertTrue(helper.toString().contains("$$Proxy")); // This is the suffix.
+
+ assertFalse(cs.check()); // Nullable.
+
+
+ instance1.dispose();
+ }
+
+ @Test
+ public void testImmediate() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1-Proxy");
+ ComponentInstance fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceNoDelegate").createComponentInstance(i1);
+
+ osgiHelper.waitForService(CheckService.class, "(service.pid=Helper)", 10000);
+
+ ServiceReference ref = osgiHelper.getServiceReference(CheckService.class.getName(), "(service.pid=Helper)");
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertTrue(helper.toString().contains("$$Proxy")); // This is the suffix.
+
+ assertTrue(cs.check());
+
+ fooProvider1.dispose();
+ instance1.dispose();
+ }
+
+ @Test
+ public void testImmediateNoService() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator-with-no-service");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceNoDelegate").createComponentInstance(i1);
+
+ osgiHelper.waitForService(CheckService.class, "(service.pid=Helper)", 10000);
+
+ ServiceReference ref = osgiHelper.getServiceReference(CheckService.class.getName(), "(service.pid=Helper)");
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ try {
+ cs.getProps();
+ fail("Exception expected");
+ } catch (RuntimeException e) {
+ //OK
+ }
+
+ instance1.dispose();
+ }
+
+ @Test
+ public void testProxyDisabled() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Disable proxy
+ System.setProperty(DependencyHandler.PROXY_SETTINGS_PROPERTY, DependencyHandler.PROXY_DISABLED);
+
+ System.out.println("Bundle context prop : " + bc.getProperty(DependencyHandler.PROXY_SETTINGS_PROPERTY));
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1-Proxy");
+ ComponentInstance fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator").createComponentInstance(i1);
+
+ osgiHelper.waitForService(CheckService.class, "(instance.name=Delegator)", 10000);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ System.out.println("helper : " + helper.toString());
+ assertNotNull(helper);
+ assertFalse(helper.toString().contains("$$Proxy")); // Not a proxy.
+
+ assertTrue(cs.check());
+
+ fooProvider1.dispose();
+ instance1.dispose();
+ System.setProperty(DependencyHandler.PROXY_SETTINGS_PROPERTY, DependencyHandler.PROXY_ENABLED);
+
+ }
+
+ @Test
+ public void testDynamicProxy() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+ // Dynamic proxy
+ System.setProperty(DependencyHandler.PROXY_TYPE_PROPERTY, DependencyHandler.DYNAMIC_PROXY);
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1-Proxy");
+ ComponentInstance fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Delegator");
+ ComponentInstance instance1 = ipojoHelper.getFactory(
+ "org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceDelegator").createComponentInstance(i1);
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull(ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref);
+
+ Properties props = cs.getProps();
+ FooService helper = (FooService) props.get("helper.fs");
+ assertNotNull(helper);
+ assertFalse(helper.toString().contains("$$Proxy")); // Dynamic proxy.
+ assertTrue(helper.toString().contains("DynamicProxyFactory"));
+ assertTrue(helper.hashCode() > 0);
+
+ assertTrue(helper.equals(helper));
+ assertFalse(helper.equals(i1)); // This is a quite stupid test...
+
+ assertTrue(cs.check());
+
+ fooProvider1.dispose();
+ instance1.dispose();
+ System.setProperty(DependencyHandler.PROXY_TYPE_PROPERTY, DependencyHandler.SMART_PROXY);
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/pom.xml
new file mode 100644
index 0000000..00db7ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-dependency-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..99a99be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckProviderParentClass.java
@@ -0,0 +1,65 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if (props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+ public void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
new file mode 100644
index 0000000..6c631f5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+
+ int modified = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+ if (fs != null) {
+ // If nullable = false and proxy, a runtime exception may be launched here
+ // catch the exception and add this to props.
+ try {
+ props.put("exception", Boolean.FALSE); // Set exception to false for checking.
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ } catch (RuntimeException e) {
+ props.put("exception", Boolean.TRUE);
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+
+
+ // Add modified
+ props.put("modified", new Integer(modified));
+
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ public void voidModify() {
+ modified ++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ protected void objectModify(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! [" + modified + "]");
+ return;
+ }
+ if(o != null && o instanceof FooService) { modified++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void refModify(ServiceReference sr) {
+ if(sr != null) { modified++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ public void bothModify(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { modified++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+
+ protected void propertiesDictionaryModify(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+
+ protected void propertiesMapModify(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ fs = o;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
new file mode 100644
index 0000000..db65a4c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CollectionCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+import java.util.*;
+
+public class CollectionCheckService implements CheckService {
+
+ Collection fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
new file mode 100644
index 0000000..4100659
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/DynCheckServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB, mapU, dictB, dictU;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
new file mode 100644
index 0000000..cccb9be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType1.java
@@ -0,0 +1,109 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
new file mode 100644
index 0000000..95cb237
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooProviderType2.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType2 implements FooService {
+
+ private int m_bar; // Service property.
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static int count = 0;
+
+
+ public boolean foo() {
+ // Update
+ if (m_foo.equals("foo")) {
+ m_foo = "bar";
+ } else {
+ m_foo = "foo";
+ }
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
new file mode 100644
index 0000000..ec7207f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FooServiceDefaultImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FooServiceDefaultImpl implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 5;
+ }
+
+ public int getInt() {
+ return 5;
+ }
+
+ public long getLong() {
+ return 5;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
new file mode 100644
index 0000000..4bbdeaf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ListCheckService.java
@@ -0,0 +1,184 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class ListCheckService implements CheckService {
+
+ List fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..2d3a6fa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodCheckServiceProvider.java
@@ -0,0 +1,134 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int mapB = 0;
+ int dictB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+ int mapU = 0;
+ int dictU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if(fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("mapB", new Integer(mapB));
+ props.put("dictB", new Integer(dictB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictU", new Integer(dictU));
+
+ if(fs != null) {
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs = o;
+ }
+ protected void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs = (FooService) context.getService(sr);
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothB++; }
+ fs = o;
+ }
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if(ref != null && o != null && o instanceof FooService) { bothU++; }
+ fs = null;
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs = o;
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs = null;
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs = o;
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
new file mode 100644
index 0000000..ff8800e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MethodMultipleCheckService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import java.util.Properties;
+
+import java.util.*;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB = 0;
+ int mapU = 0;
+ int dictB = 0, dictU=0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for(int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) { return null; }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", check());
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapU", mapU);
+ props.put("mapB", mapB);
+ props.put("dictU", dictU);
+ props.put("dictB", dictB);
+ props.put("boolean", getBoolean());
+ props.put("int", getInt());
+ props.put("long", getLong());
+ props.put("double", getDouble());
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if(o != null && o instanceof FooService) { objectB++; }
+ fs.add(o);
+ }
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ fs.add(context.getService(sr));
+ }
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ fs.add(o);
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ fs.remove(o);
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ fs.add(o);
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ fs.remove(o);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
new file mode 100644
index 0000000..0e3007d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleCheckService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ int mapB, mapU, dictB, dictU;
+
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ props.put("mapB", new Integer(mapB));
+ props.put("mapU", new Integer(mapU));
+ props.put("dictB", new Integer(dictB));
+ props.put("dictU", new Integer(dictU));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+ protected void propertiesMapBind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ }
+ protected void propertiesMapUnbind(FooService o, Map props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapU++; }
+ }
+
+ protected void propertiesDictionaryBind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ }
+ protected void propertiesDictionaryUnbind(FooService o, Dictionary props) {
+ if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictU++; }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..63eb7bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/MultipleFilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int binded;
+
+ public MultipleFilterCheckSubscriber(){
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(binded));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ binded++;
+ }
+ private void Unbind() {
+ binded--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
new file mode 100644
index 0000000..4fd100a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/ParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components;
+
+public class ParentClass {
+
+ public void parentStart() {
+
+ }
+
+ public void parentStop() {
+
+ }
+
+ protected String[] strings;
+
+ protected String string;
+
+ protected int upStrings;
+
+ protected int upString;
+
+ public void updateStrings(String[] bb) {
+ strings = bb;
+ upStrings++;
+ }
+
+ public void updateString(String bb) {
+ string = bb;
+ upString++;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
new file mode 100644
index 0000000..9ac13e2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/RankedFooProviderType1.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() {
+ return m_grade; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
new file mode 100644
index 0000000..f25a95f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/SetCheckService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+public class SetCheckService implements CheckService {
+
+ Set fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r & ((FooService) it.next()).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ Iterator it = fs.iterator();
+ while(it.hasNext()) {
+ r = r + ((FooService) it.next()).getLong();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
new file mode 100644
index 0000000..fe3e00b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/VectorCheckService.java
@@ -0,0 +1,159 @@
+/*
+ * 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.test.components;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+import java.util.Vector;
+
+public class VectorCheckService implements CheckService {
+
+ Vector fs;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getDouble();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ // simpleB++;
+ }
+
+ public void voidUnbind() {
+ // simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ // objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
new file mode 100644
index 0000000..5295912
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/CheckServiceProvider.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ FooService fs2;
+
+ FooService[] fss;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("fs", new Integer(fs.getInt()));
+ props.put("fs2", new Integer(fs2.getInt()));
+
+ int[] grades = new int[fss.length];
+
+ for (int i = 0; i < grades.length; i++) {
+ grades[i] = fss[i].getInt();
+ }
+
+ props.put("fss", grades);
+
+ return props;
+ }
+
+ void bind(FooService svc) {
+ fs2 = svc;
+ }
+
+ void unbind(FooService svc) {
+ fs2 = null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
new file mode 100644
index 0000000..3d09a97
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradeComparator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.comparator;
+
+import org.osgi.framework.ServiceReference;
+
+import java.util.Comparator;
+
+public class GradeComparator implements Comparator {
+
+ public int compare(Object arg0, Object arg1) {
+ ServiceReference ref0 = null;
+ ServiceReference ref1 = null;
+ Integer grade0 = null;
+ Integer grade1 = null;
+ if (arg0 instanceof ServiceReference) {
+ ref0 = (ServiceReference) arg0;
+ grade0 = (Integer) ref0.getProperty("grade");
+ }
+ if (arg1 instanceof ServiceReference) {
+ ref1 = (ServiceReference) arg1;
+ grade1 = (Integer) ref1.getProperty("grade");
+ }
+
+ if (ref0 != null && ref1 != null
+ && grade0 != null && grade1 != null) {
+ return grade1.compareTo(grade0); // Best grade first.
+ } else {
+ return 0; // Equals
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
new file mode 100644
index 0000000..0309800
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/comparator/GradedFooServiceProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.components.comparator;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class GradedFooServiceProvider implements FooService {
+
+
+ private int grade;
+
+ public boolean foo() {
+ return grade > 0;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return grade;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java
new file mode 100644
index 0000000..d234467
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.test.components.context;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A component using a Foo service.
+ * The foo service is selected using a contextual filter.
+ * The filter is set within the instance configuration.
+ */
+@Component
+@Provides
+public class ContextualFilterConsumer implements CheckService {
+
+ @Requires(id = "foo")
+ private FooService foo;
+
+ @Override
+ public boolean check() {
+ return foo != null;
+ }
+
+ @Override
+ public Properties getProps() {
+ Properties properties = new Properties();
+ properties.put("id", foo.getInt());
+ return properties;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider1.java
new file mode 100644
index 0000000..42e0a1c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider1.java
@@ -0,0 +1,75 @@
+/*
+ * 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.test.components.context;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A simple foo provider with id 1
+ */
+@Component
+@Provides(properties =
+ @StaticServiceProperty(name="id", value = "1", type = "string"))
+// We don't instantiate it here as it may break other tests.
+public class Provider1 implements FooService {
+
+ @Override
+ public boolean foo() {
+ return false;
+ }
+
+ @Override
+ public Properties fooProps() {
+ return null;
+ }
+
+ @Override
+ public Boolean getObject() {
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return false;
+ }
+
+ @Override
+ public int getInt() {
+ // The id.
+ return 1;
+ }
+
+ @Override
+ public long getLong() {
+ // The id.
+ return 1;
+ }
+
+ @Override
+ public double getDouble() {
+ // The id
+ return 1;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider2.java
new file mode 100644
index 0000000..8c2f95b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/Provider2.java
@@ -0,0 +1,75 @@
+/*
+ * 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.test.components.context;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.StaticServiceProperty;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A simple foo provider with id 2
+ */
+@Component
+@Provides(properties =
+ @StaticServiceProperty(name="id", value = "2", type = "string"))
+// We don't instantiate it here as it may break other tests.
+public class Provider2 implements FooService {
+
+ @Override
+ public boolean foo() {
+ return false;
+ }
+
+ @Override
+ public Properties fooProps() {
+ return null;
+ }
+
+ @Override
+ public Boolean getObject() {
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return false;
+ }
+
+ @Override
+ public int getInt() {
+ // The id.
+ return 2;
+ }
+
+ @Override
+ public long getLong() {
+ // The id.
+ return 2;
+ }
+
+ @Override
+ public double getDouble() {
+ // The id
+ return 2;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/NullPointerExceptionBinder.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/NullPointerExceptionBinder.java
new file mode 100644
index 0000000..5dfe865
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/error/NullPointerExceptionBinder.java
@@ -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.runtime.core.test.components.error;
+
+import org.apache.felix.ipojo.annotations.*;
+import org.apache.felix.ipojo.architecture.Architecture;
+
+
+
+@Component(immediate=true)
+/**
+ * Throws an NPE when binding a service.
+ */
+public class NullPointerExceptionBinder {
+
+ @Bind(id="instances", aggregate=true, optional=true)
+ public void bindInstance(Architecture instance) {
+ throw new NullPointerException("something went terribly wrong");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
new file mode 100644
index 0000000..91c33e7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckProvider.java
@@ -0,0 +1,90 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckProvider implements CheckService, FooService {
+
+ private String m_toto;
+
+ private int bind;
+
+ private int unbind;
+
+ public FilterCheckProvider() {
+ m_toto = "A";
+ }
+
+ public boolean check() {
+ if (m_toto.equals("A")) {
+ m_toto = "B";
+ return true;
+ } else {
+ m_toto = "A";
+ return false;
+ }
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bind - unbind));
+ return null;
+ }
+
+ private void Bind() {
+ bind++;
+ }
+
+ private void Unbind() {
+ unbind++;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
new file mode 100644
index 0000000..5ffa4bd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/FilterCheckSubscriber.java
@@ -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.felix.ipojo.runtime.core.test.components.filter;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class FilterCheckSubscriber implements CheckService {
+
+ private FooService m_foo;
+
+ private int bound;
+
+ public FilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ m_foo.foo();
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Nullable", new Boolean(m_foo instanceof Nullable));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
new file mode 100644
index 0000000..0ee898c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/filter/MultipleFilterCheckSubscriber.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.components.filter;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class MultipleFilterCheckSubscriber implements CheckService {
+
+ private FooService[] m_foo;
+
+ private int bound;
+
+ public MultipleFilterCheckSubscriber() {
+ }
+
+ public boolean check() {
+ for (int i = 0; i < m_foo.length; i++) {
+ m_foo[i].foo();
+ }
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("Bind", new Integer(bound));
+ props.put("Size", new Integer(m_foo.length));
+ return props;
+ }
+
+ private void Bind() {
+ bound++;
+ }
+
+ private void Unbind() {
+ bound--;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java
new file mode 100644
index 0000000..b76b34d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.components.identification;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Set;
+
+/**
+ * A component reproducing FELIX-4250 - Specification deduction broken when the method does not start with the 'bind'
+ * prefix (https://issues.apache.org/jira/browse/FELIX-4250).
+ *
+ * The add and remove methods should be attached to the same dependency (id = MyService)
+ * The set and unset methods should be attached to the same dependency (id = MyOtherService)
+ */
+@Component
+public class ComponentWithCustomMethods {
+
+ Set<FooService> myServices;
+
+ Set<Call> myOtherServices;
+
+ @Bind(optional=true, aggregate=true)
+ public void addMyService(FooService newService) {
+ myServices.add(newService);
+ }
+
+ @Unbind
+ public void removeMyService(FooService oldService) {
+ myServices.remove(oldService);
+ }
+
+
+ @Bind(optional=true, aggregate=true)
+ public void setMyOtherService(Call newService) {
+ myOtherServices.add(newService);
+ }
+
+ @Unbind
+ public void unsetMyOtherService(Call oldService) {
+ myOtherServices.remove(oldService);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
new file mode 100644
index 0000000..646bfbb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C1.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C1 implements Call {
+
+ public String callMe() {
+ return "called";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
new file mode 100644
index 0000000..b4c0c88
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.components.inner;
+
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+
+public class C2 {
+
+ private Call c1;
+
+ public String authenticate() {
+ return c1.callMe();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
new file mode 100644
index 0000000..7f71de4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/C3.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.components.inner;
+
+public class C3 {
+
+ private C2 c2;
+
+ public MyFilter getFilter() {
+ return new MyFilter() {
+ public String authenticate() {
+ System.out.println("My Filter ...");
+ String r = c2.authenticate();
+ System.out.println(" ... " + r);
+ return r;
+ }
+ };
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
new file mode 100644
index 0000000..e3e64cd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/inner/MyFilter.java
@@ -0,0 +1,26 @@
+/*
+ * 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.test.components.inner;
+
+public interface MyFilter {
+
+ public String authenticate();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultHelloService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultHelloService.java
new file mode 100644
index 0000000..1267dc1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultHelloService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.components.leak;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+/**
+ * A implementation of the Hello Service
+ * (FELIX-4247 Memory leak with ServiceUsage and inner class (Listener style))
+ */
+@Component
+@Provides
+public class DefaultHelloService implements HelloService {
+ @Override
+ public String hello(final String name) {
+ System.out.println("Hello "+ name);
+ return "Hello " + name;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultLeakingService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultLeakingService.java
new file mode 100644
index 0000000..b8b735a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/leak/DefaultLeakingService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.components.leak;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+import org.apache.felix.ipojo.runtime.core.test.services.LeakingService;
+import org.apache.felix.ipojo.runtime.core.test.services.Listener;
+
+/**
+ * A component reproducing the leak (FELIX-4247 Memory leak with ServiceUsage and inner class (Listener style)).
+ */
+@Component
+@Provides
+@Instantiate
+public class DefaultLeakingService implements LeakingService {
+
+ @Requires(optional = true)
+ HelloService service;
+
+ private Listener listener;
+
+ public DefaultLeakingService() {
+ listener = new Listener() {
+ // When the Hello Service will become unavailable, calling doSomething should use a nullable object.
+ // Therefore, it should return 'null'.
+ @Override
+ public String doSomething() {
+ return service.hello("iPOJO");
+ }
+ };
+ }
+
+ @Override
+ public Listener getListener() {
+ return listener;
+ }
+
+ @Override
+ public String executeListener() {
+ return listener.doSomething();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
new file mode 100644
index 0000000..398d342
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/optional/MyComponent.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components.optional;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.service.log.LogService;
+
+
+@Component(immediate=true, name="optional-log-cons")
+public class MyComponent {
+
+ @Requires(optional=true, proxy=false)
+ private LogService log;
+
+
+ public MyComponent() {
+ System.out.println("Created ! : " + (log instanceof Nullable) + " - " + log);
+ log.log(LogService.LOG_INFO, "Created !");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
new file mode 100644
index 0000000..a89dd43
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
new file mode 100644
index 0000000..f55cfcc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/CheckServiceProvider.java
@@ -0,0 +1,91 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
new file mode 100644
index 0000000..93c3737
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/DynCheckServiceProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class DynCheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("int", new Integer(fs.getInt()));
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (sr != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
new file mode 100644
index 0000000..5b13c7b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodCheckServiceProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MethodCheckServiceProvider implements CheckService {
+
+ FooService fs;
+
+ BundleContext context;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public MethodCheckServiceProvider(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ } else {
+ props.put("result", new Boolean(false));
+ }
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+
+ if (fs != null) {
+ if (fs.getObject() != null) {
+ props.put("object", fs.getObject());
+ }
+ }
+
+ return props;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs = o;
+ }
+
+ protected void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs = null;
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs = (FooService) context.getService(sr);
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ context.ungetService(sr);
+ fs = null;
+ }
+
+ protected void bothBind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothB++;
+ }
+ fs = o;
+ }
+
+ protected void bothUnbind(FooService o, ServiceReference ref) {
+ if (ref != null && o != null && o instanceof FooService) {
+ bothU++;
+ }
+ fs = null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
new file mode 100644
index 0000000..05481af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MethodMultipleCheckService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class MethodMultipleCheckService implements CheckService {
+
+ List fs = new ArrayList();
+ BundleContext context;
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public MethodMultipleCheckService(BundleContext bc) {
+ context = bc;
+ }
+
+ public boolean check() {
+ boolean r = fs.size() != 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r & ((FooService) fs.get(i)).foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.size(); i++) {
+ r = r + ((FooService) fs.get(i)).getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+// private Object getObject() {
+// boolean r = true;
+// for(int i = 0; i < fs.length; i++) {
+// r = r && ((Boolean) fs[i].getObject()).booleanValue();
+// }
+// return new Boolean(r);
+// }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ fs.add(o);
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ fs.remove(o);
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ fs.add(context.getService(sr));
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ fs.remove(context.getService(sr));
+ context.ungetService(sr);
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.add(o);
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ fs.remove(o);
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
new file mode 100644
index 0000000..f437e09
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/MultipleCheckService.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class MultipleCheckService implements CheckService {
+
+ FooService fs[];
+
+ int simpleB = 0;
+
+ int objectB = 0;
+
+ int refB = 0;
+
+ int bothB = 0;
+
+ int simpleU = 0;
+
+ int objectU = 0;
+
+ int refU = 0;
+
+ int bothU = 0;
+
+ public boolean check() {
+ boolean r = fs.length != 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r & fs[i].foo();
+ }
+ return r;
+ }
+
+ private boolean getBoolean() {
+ return check();
+ }
+
+ private int getInt() {
+ int r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ private long getLong() {
+ long r = 0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getLong();
+ }
+ return r;
+ }
+
+ private double getDouble() {
+ double r = 0.0;
+ for (int i = 0; i < fs.length; i++) {
+ r = r + fs[i].getInt();
+ }
+ return r;
+ }
+
+ protected Object doNothing(Object o, String s) {
+ return null;
+ }
+
+ // private Object getObject() {
+ // boolean r = true;
+ // for(int i = 0; i < fs.length; i++) {
+ // r = r && ((Boolean) fs[i].getObject()).booleanValue();
+ // }
+ // return new Boolean(r);
+ // }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("result", new Boolean(check()));
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ props.put("boolean", new Boolean(getBoolean()));
+ props.put("int", new Integer(getInt()));
+ props.put("long", new Long(getLong()));
+ props.put("double", new Double(getDouble()));
+
+ return props;
+ }
+
+ public void voidBind() {
+ simpleB++;
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+ public void objectBind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectB++;
+ }
+ }
+
+ public void objectUnbind(FooService o) {
+ if (o != null && o instanceof FooService) {
+ objectU++;
+ }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if (sr != null) {
+ refB++;
+ }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if (sr != null) {
+ refU++;
+ }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothB++;
+ }
+ }
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if (o != null && o instanceof FooService && sr != null) {
+ bothU++;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
new file mode 100644
index 0000000..e2f9bc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/policies/RankedFooProviderType1.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.policies;
+
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+public class RankedFooProviderType1 implements FooService {
+ private int m_grade;
+
+
+ public boolean foo() {
+ m_grade = m_grade + 2;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("grade", new Integer(m_grade));
+
+ return p;
+ }
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return m_grade;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
new file mode 100644
index 0000000..14c69c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceDelegator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceDelegator implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceDelegator(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
new file mode 100644
index 0000000..ebc94c5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceGetAndDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceGetAndDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ public CheckServiceGetAndDelegate(BundleContext bc) {
+ helper = new Helper(bc, fs);
+ }
+
+ public boolean check() {
+ fs.foo();
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ fs.getBoolean();
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
new file mode 100644
index 0000000..6db5841
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceNoDelegate.java
@@ -0,0 +1,61 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class CheckServiceNoDelegate implements CheckService {
+
+ private FooService fs;
+
+ private Helper helper;
+
+ private BundleContext context;
+
+ public CheckServiceNoDelegate(BundleContext bc) {
+ context = bc;
+ helper = new Helper(context, fs);
+ }
+
+ public void start() {
+ helper.publish();
+ }
+
+ public void stop() {
+ helper.unpublish();
+ }
+
+ public boolean check() {
+ // Don't access the service
+ // Just delegate
+ return helper.check();
+ }
+
+ public Properties getProps() {
+ // Don't access the service
+ // Just delegate
+ return helper.getProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
new file mode 100644
index 0000000..5c04dac
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/CheckServiceUsingStringService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+
+import java.util.AbstractMap;
+import java.util.Properties;
+
+public class CheckServiceUsingStringService implements CheckService {
+
+ private String string;
+ private AbstractMap map;
+
+
+ public CheckServiceUsingStringService() {
+ System.out.println("Service : " + string);
+ System.out.println("Map : " + map);
+ }
+
+ public boolean check() {
+ return string != null
+ && map != null;
+ }
+
+ public Properties getProps() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
new file mode 100644
index 0000000..dd86961
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/proxy/Helper.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.components.proxy;
+
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+public class Helper implements CheckService {
+
+
+ private FooService fs;
+ private BundleContext context;
+ private ServiceRegistration reg;
+
+ public Helper(BundleContext bc, FooService svc) {
+ fs = svc;
+ context = bc;
+ }
+
+ public void publish() {
+ Dictionary<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_PID, "Helper");
+ context.registerService(CheckService.class, this, props);
+ reg = context.registerService(CheckService.class.getName(), this, props);
+ }
+
+ public void unpublish() {
+ if (reg != null) {
+ reg.unregister();
+ }
+ reg = null;
+ }
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ fs.getBoolean();
+ props.put("helper.fs", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
new file mode 100644
index 0000000..3f4e34c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Call.java
@@ -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.felix.ipojo.runtime.core.test.services;
+
+public interface Call {
+
+
+ public String callMe();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
new file mode 100644
index 0000000..e4366ab
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
new file mode 100644
index 0000000..9b8e12b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
new file mode 100644
index 0000000..420be52
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.test.services;
+
+/**
+ * A service used to reproduce the leak bug (FELIX-4247 Memory leak with ServiceUsage and inner class (Listener
+ * style)).
+ */
+public interface HelloService {
+ String hello(String name);
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/LeakingService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/LeakingService.java
new file mode 100644
index 0000000..5f07aad
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/LeakingService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.services;
+
+/**
+ * A service providing a listener.
+ * USed to reproduce the leak bug (FELIX-4247 Memory leak with ServiceUsage and inner class (Listener style))
+ */
+public interface LeakingService {
+ Listener getListener();
+ String executeListener();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Listener.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Listener.java
new file mode 100644
index 0000000..f39a82f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/Listener.java
@@ -0,0 +1,28 @@
+/*
+ * 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.test.services;
+
+/**
+ * A listener to reproduce the listener leak (FELIX-4247 Memory leak with ServiceUsage and inner class (Listener
+ * style))
+ */
+public interface Listener {
+ String doSomething();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-comparator.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-comparator.xml
new file mode 100644
index 0000000..1fb7e18
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-comparator.xml
@@ -0,0 +1,55 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradedFooServiceProvider"
+ name="COMPARATOR-gradedFooProvider">
+ <provides>
+ <property field="grade"/>
+ </provides>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicCheckService">
+ <provides/>
+ <requires field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.test.components.comparator.CheckServiceProvider"
+ name="COMPARATOR-DynamicPriorityCheckService">
+ <provides/>
+ <requires policy="dynamic-priority" field="fs" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" field="fss" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator"/>
+ <requires policy="dynamic-priority" comparator="org.apache.felix.ipojo.runtime.core.test.components.comparator.GradeComparator">
+ <callback type="bind" method="bind"/>
+ <callback type="unbind" method="unbind"/>
+ </requires>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-filter.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-filter.xml
new file mode 100644
index 0000000..975b5b5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata-filter.xml
@@ -0,0 +1,141 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+
+ <!-- Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimpleFilterCheckServiceProvider" architecture="true">
+ <provides>
+ <property field="m_toto" name="toto" value="A" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFromCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" from="A" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckProvider"
+ name="SimplePIDCheckServiceProvider" architecture="true">
+ <provides>
+ <property type="String" name="service.pid" />
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="SimpleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Simple Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1"
+ optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.FilterCheckSubscriber"
+ name="OptionalSimpleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Aggregate filter Dependencies-->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber" architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="MultipleFilterCheckServiceSubscriber2" architecture="true">
+ <requires field="m_foo" id="id2" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Optional Aggregate Filter Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber"
+ architecture="true">
+ <requires field="m_foo" filter="(toto=B)" id="id1" proxy="false"
+ optional="true">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.filter.MultipleFilterCheckSubscriber"
+ name="OptionalMultipleFilterCheckServiceSubscriber2"
+ architecture="true">
+ <requires field="m_foo" id="id2" optional="true" proxy="false">
+ <callback type="bind" method="Bind" />
+ <callback type="unbind" method="Unbind" />
+ </requires>
+ <provides />
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..34a23b4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/resources/metadata.xml
@@ -0,0 +1,519 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<!--
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType1"
+ name="FooProviderType-1" architecture="true">
+ <provides />
+ </component>
+
+ <!-- Simple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedSimpleCheckServiceProvider" architecture="true">
+ <requires field="fs" />
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedVoidCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedObjectCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedRefCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedBothCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedMapCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDictCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" proxy="true"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ProxiedDoubleCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <requires field="fs" />
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MObjectCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MRefCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MBothCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MMapCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodCheckServiceProvider"
+ name="MDictCheckServiceProvider" architecture="true">
+ <requires>
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Simple & Optional Dependencies -->
+ <!-- used for architecture test -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="SimpleOptionalCheckServiceProvider" architecture="true">
+ <requires field="fs" optional="true" id="FooService" proxy="false"/>
+ <provides />
+ </component>
+
+ <!-- Multiple Dependencies -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="VoidMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="ObjectMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="RefMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="BothMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="MapMultipleCheckServiceProvider" architecture="true">
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="DictMultipleCheckServiceProvider" architecture="true" >
+ <requires field="fs" proxy="false">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MObjectMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MRefMultipleCheckServiceProvider" architecture="true">
+ <requires
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"
+ aggregate="true">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MBothMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MMapMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MethodMultipleCheckService"
+ name="MDictMultipleCheckServiceProvider" architecture="true">
+ <requires aggregate="true">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ </requires>
+ <provides />
+ </component>
+
+ <!-- Multiple & Optional Dependencies -->
+ <!-- Used in architecture tests -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.MultipleCheckService"
+ name="SimpleOptionalMultipleCheckServiceProvider"
+ architecture="true">
+ <requires field="fs" optional="true" proxy="false"/>
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as List -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="SimpleListCheckServiceProvider" architecture="true">
+ <requires proxy="false"
+ field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.ListCheckService"
+ name="OptionalListCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false"
+ specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Vector -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="SimpleVectorCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind"/>
+ <callback type="unbind" method="objectUnbind"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.VectorCheckService"
+ name="OptionalVectorCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Set -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="SimpleSetCheckServiceProvider" architecture="true">
+ <requires proxy="false" field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.SetCheckService"
+ name="OptionalSetCheckServiceProvider"
+ architecture="true">
+ <requires proxy="false" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true" />
+ <provides />
+ </component>
+
+ <!-- Aggregate dependency as Collection -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="SimpleCollectionCheckServiceProvider" architecture="true">
+ <requires field="fs" specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" proxy="false"/>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CollectionCheckService"
+ name="OptionalCollectionCheckServiceProvider"
+ architecture="true">
+ <requires specification="org.apache.felix.ipojo.runtime.core.test.services.FooService" field="fs" optional="true"
+ proxy="false"
+ />
+ <provides />
+ </component>
+
+
+ <!-- Modify method test -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.FooProviderType2"
+ name="FooProviderType-Updatable" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo" value="foo"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="VoidModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="voidBind" />
+ <callback type="unbind" method="voidUnbind" />
+ <callback type="modified" method="voidModify"/>
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="ObjectModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="objectBind" />
+ <callback type="unbind" method="objectUnbind" />
+ <callback type="modified" method="objectModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="RefModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="refBind" />
+ <callback type="unbind" method="refUnbind" />
+ <callback type="modified" method="refModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="BothModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="bothBind" />
+ <callback type="unbind" method="bothUnbind" />
+ <callback type="modified" method="bothModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="MapModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesMapBind" />
+ <callback type="unbind" method="propertiesMapUnbind" />
+ <callback type="modified" method="propertiesMapModify" />
+ </requires>
+ <provides />
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.CheckServiceProvider"
+ name="DictModifyCheckServiceProvider" architecture="true">
+ <requires field="fs">
+ <callback type="bind" method="propertiesDictionaryBind" />
+ <callback type="unbind" method="propertiesDictionaryUnbind" />
+ <callback type="modified" method="propertiesDictionaryModify" />
+ </requires>
+ <provides />
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceUsingStringService"
+ immediate="true">
+ <provides/>
+ <requires field="string"/>
+ <requires field="map"/>
+ </component>
+
+ <!-- Inner + Proxy mix -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C1">
+ <provides/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C2">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C2"/>
+ <requires field="c1"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.test.components.inner.C3">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.test.components.inner.C3"/>
+ <requires field="c2"/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
new file mode 100644
index 0000000..8af42c8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.dependencies;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.test.components.inner"
+ );
+ }
+
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[] {
+ wrappedBundle(maven("org.easytesting", "fest-assert").versionAsInProject()),
+ wrappedBundle(maven("org.easytesting", "fest-util").versionAsInProject())
+ };
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCollectionMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCollectionMultipleDependencies.java
new file mode 100644
index 0000000..bded88c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestCollectionMultipleDependencies.java
@@ -0,0 +1,245 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestCollectionMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleCollectionCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("OptionalCollectionCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedMultipleDependencies.java
new file mode 100644
index 0000000..a252ba7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedMultipleDependencies.java
@@ -0,0 +1,507 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleMultipleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidMultipleCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothMultipleCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MapMultipleCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("DictMultipleCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.INVALID);
+
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.INVALID);
+
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance5.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance6.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance7.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedSimpleDependencies.java
new file mode 100644
index 0000000..f869e8d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDelayedSimpleDependencies.java
@@ -0,0 +1,373 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDelayedSimpleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleCheckServiceProvider").createComponentInstance(i1);
+ instance1.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidCheckServiceProvider").createComponentInstance(i2);
+ instance2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MapCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("DictCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ instance1.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+ fooProvider.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+ fooProvider.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+ fooProvider.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance1.stop();
+ }
+
+ @Test public void testVoid() {
+ instance2.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance2.stop();
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDependencyArchitecture.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDependencyArchitecture.java
new file mode 100644
index 0000000..4e0e636
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestDependencyArchitecture.java
@@ -0,0 +1,702 @@
+/*
+ * 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.test.dependencies;
+
+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.InstanceDescription;
+import org.apache.felix.ipojo.handlers.dependency.Dependency;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestDependencyArchitecture extends Common {
+
+ ComponentInstance fooProvider1, fooProvider2;
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "ProxiedSimple");
+ instance5 = ipojoHelper.getFactory("ProxiedSimpleCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("SimpleOptionalCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Multiple");
+ instance3 = ipojoHelper.getFactory("SimpleMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "OptionalMultiple");
+ instance4 = ipojoHelper.getFactory("SimpleOptionalMultipleCheckServiceProvider").createComponentInstance(i4);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ private DependencyHandlerDescription getDependencyDesc(InstanceDescription id) {
+ DependencyHandlerDescription handler = (DependencyHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:requires");
+ if (handler == null) {
+ fail("Dependency Handler not found");
+ return null;
+ } else {
+ return handler;
+ }
+ }
+
+ private DependencyDescription getDependencyDescBySpecification(
+ PrimitiveInstanceDescription id, String spec) {
+ return id.getDependency(spec);
+ }
+
+ private ProvidedServiceHandlerDescription getPSDesc(InstanceDescription id) {
+ ProvidedServiceHandlerDescription handler = (ProvidedServiceHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:provides");
+ if (handler == null) {
+ fail("Provided Service Handler not found");
+ return null;
+ } else {
+ return handler;
+ }
+ }
+
+ @Test
+ public void testSimpleDependency() {
+ ServiceReference arch_dep = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_dep);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+
+ // Check dependency handler invalidity
+ DependencyHandlerDescription dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ // Check dependency metadata
+ assertEquals("Check dependency interface", dhd.getDependencies()[0].getInterface(), FooService.class.getName());
+ assertEquals("Check dependency id", dhd.getDependencies()[0].getId(), FooService.class.getName());
+ assertFalse("Check dependency cardinality", dhd.getDependencies()[0].isMultiple());
+ assertFalse("Check dependency optionality", dhd.getDependencies()[0].isOptional());
+ assertNull("Check dependency ref -1", dhd.getDependencies()[0].getServiceReferences());
+ assertFalse("Check dependency proxy", dhd.getDependencies()[0].isProxy());
+
+ fooProvider1.start();
+
+ ServiceReference arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ PrimitiveInstanceDescription id_ps = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh = getPSDesc(id_ps);
+ assertEquals("Check POJO creation", id_ps.getCreatedObjects().length, 1);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ fooProvider1.start();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+ psh = getPSDesc(id_ps);
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+
+ assertEquals("Check dependency ref -3", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ psh = getPSDesc(id_ps);
+
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ id_dep = null;
+ cs = null;
+ getContext().ungetService(arch_dep);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testProxiedSimpleDependency() {
+ ServiceReference arch_dep = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_dep);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+
+ // Check dependency handler invalidity
+ DependencyHandlerDescription dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ // Check dependency metadata
+ assertEquals("Check dependency interface", dhd.getDependencies()[0].getInterface(), FooService.class.getName());
+ assertEquals("Check dependency id", dhd.getDependencies()[0].getId(), FooService.class.getName());
+ assertFalse("Check dependency cardinality", dhd.getDependencies()[0].isMultiple());
+ assertFalse("Check dependency optionality", dhd.getDependencies()[0].isOptional());
+ assertNull("Check dependency ref -1", dhd.getDependencies()[0].getServiceReferences());
+ assertTrue("Check dependency proxy", dhd.getDependencies()[0].isProxy());
+
+ fooProvider1.start();
+
+ ServiceReference arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ PrimitiveInstanceDescription id_ps = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh = getPSDesc(id_ps);
+ assertEquals("Check POJO creation", id_ps.getCreatedObjects().length, 1);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ fooProvider1.start();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+ psh = getPSDesc(id_ps);
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+
+ assertEquals("Check dependency ref -3", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ psh = getPSDesc(id_ps);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ id_dep = null;
+ cs = null;
+ getContext().ungetService(arch_dep);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testOptionalDependency() {
+ ServiceReference arch_dep = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_dep);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check dependency handler invalidity
+ DependencyHandlerDescription dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ // Check dependency metadata
+ assertEquals("Check dependency interface", dhd.getDependencies()[0].getInterface(), FooService.class.getName());
+ assertEquals("Check dependency id", dhd.getDependencies()[0].getId(), "FooService");
+ assertFalse("Check dependency cardinality", dhd.getDependencies()[0].isMultiple());
+ assertTrue("Check dependency optionality", dhd.getDependencies()[0].isOptional());
+ assertNull("Check dependency ref -1", dhd.getDependencies()[0].getServiceReferences());
+
+ fooProvider1.start();
+
+ ServiceReference arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ PrimitiveInstanceDescription id_ps = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh = getPSDesc(id_ps);
+ assertEquals("Check POJO creation", id_ps.getCreatedObjects().length, 1);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ fooProvider1.start();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ arch_ps = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps.getState() == ComponentInstance.VALID);
+ psh = getPSDesc(id_ps);
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+
+ assertEquals("Check dependency ref -3", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps = ((Architecture) osgiHelper.getRawServiceObject(arch_ps)).getInstanceDescription();
+ psh = getPSDesc(id_ps);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ id_dep = null;
+ cs = null;
+ getContext().ungetService(arch_dep);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testMultipleDependency() {
+ ServiceReference arch_dep = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_dep);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);
+
+ // Check dependency handler invalidity
+ DependencyHandlerDescription dhd = getDependencyDesc(id_dep);
+ DependencyDescription dd = getDependencyDescBySpecification(id_dep, FooService.class.getName());
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+ assertTrue("Check dependency invalidity", dd.getState() == Dependency.UNRESOLVED);
+
+
+ // Check dependency metadata
+ assertEquals("Check dependency interface", dhd.getDependencies()[0].getInterface(), FooService.class.getName());
+ assertTrue("Check dependency cardinality", dhd.getDependencies()[0].isMultiple());
+ assertFalse("Check dependency optionality", dhd.getDependencies()[0].isOptional());
+ assertNull("Check dependency ref -1", dhd.getDependencies()[0].getServiceReferences());
+
+ assertEquals("Check dependency interface", dd.getSpecification(), FooService.class.getName());
+ assertTrue("Check dependency cardinality", dd.isMultiple());
+ assertFalse("Check dependency optionality", dd.isOptional());
+ assertNull("Check dependency ref -1", dd.getServiceReferences());
+ assertFalse("Check dependency proxy", dhd.getDependencies()[0].isProxy());
+
+ fooProvider1.start();
+
+ ServiceReference arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ PrimitiveInstanceDescription id_ps1 = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_ps1.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+ assertEquals("Check used ref - 1 (" + dhd.getDependencies()[0].getUsedServices().size() + ")", dhd.getDependencies()[0].getUsedServices().size(), 0);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh = getPSDesc(id_ps1);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+
+ // Start a second foo service provider
+ fooProvider2.start();
+
+ arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ ServiceReference arch_ps2 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ assertNotNull("Check architecture 2 availability", arch_ps2);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ PrimitiveInstanceDescription id_ps2 = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps2)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps1.getState() == ComponentInstance.VALID);
+ assertTrue("Check instance 2 invalidity - 1", id_ps2.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 3 ", dhd.getDependencies()[0].getServiceReferences().size(), 2);
+ assertEquals("Check used ref - 2 ", dhd.getDependencies()[0].getUsedServices().size(), 1); // provider 2 not already used
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ //id_ps2 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh1 = getPSDesc(id_ps1);
+ ProvidedServiceHandlerDescription psh2 = getPSDesc(id_ps2);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+ assertEquals("Check POJO creation", id_ps2.getCreatedObjects().length, 1);
+ assertEquals("Check used ref - 3 (" + dhd.getDependencies()[0].getUsedServices().size() + ")", dhd.getDependencies()[0].getUsedServices().size(), 2);
+
+ fooProvider2.stop();
+
+ arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id_ps1.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+ assertEquals("Check used ref - 4 ", dhd.getDependencies()[0].getUsedServices().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ psh = getPSDesc(id_ps1);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+ assertEquals("Check used ref - 5 ", dhd.getDependencies()[0].getUsedServices().size(), 1);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertFalse("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ fooProvider2.start();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ arch_ps2 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+
+ assertTrue("Check instance invalidity - 1", id_ps2.getState() == ComponentInstance.VALID);
+
+ psh = getPSDesc(id_ps2);
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+
+ assertEquals("Check dependency ref -3", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+ assertEquals("Check used ref - 6 ", dhd.getDependencies()[0].getUsedServices().size(), 0);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ psh = getPSDesc(id_ps2);
+ assertEquals("Check used ref - 7 ", dhd.getDependencies()[0].getUsedServices().size(), 1);
+
+ fooProvider2.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertFalse("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertFalse("Check dependency handler invalidity", dhd.isValid());
+
+ id_dep = null;
+ cs = null;
+ getContext().ungetService(arch_dep);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testMultipleOptionalDependency() {
+ ServiceReference arch_dep = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_dep);
+ PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.VALID);
+
+ // Check dependency handler invalidity
+ DependencyHandlerDescription dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ // Check dependency metadata
+ assertEquals("Check dependency interface", dhd.getDependencies()[0].getInterface(), FooService.class.getName());
+ assertTrue("Check dependency cardinality", dhd.getDependencies()[0].isMultiple());
+ assertTrue("Check dependency optionality", dhd.getDependencies()[0].isOptional());
+ assertNull("Check dependency ref -1", dhd.getDependencies()[0].getServiceReferences());
+
+ fooProvider1.start();
+
+ ServiceReference arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ PrimitiveInstanceDescription id_ps1 = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps1.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh = getPSDesc(id_ps1);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+
+ // Start a second foo service provider
+ fooProvider2.start();
+
+ arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ ServiceReference arch_ps2 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ assertNotNull("Check architecture 2 availability", arch_ps2);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ PrimitiveInstanceDescription id_ps2 = (PrimitiveInstanceDescription) ((Architecture) osgiHelper.getRawServiceObject(arch_ps2)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps1.getState() == ComponentInstance.VALID);
+ assertTrue("Check instance 2 invalidity - 1", id_ps2.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 3 ", dhd.getDependencies()[0].getServiceReferences().size(), 2);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ //id_ps2 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ ProvidedServiceHandlerDescription psh1 = getPSDesc(id_ps1);
+ ProvidedServiceHandlerDescription psh2 = getPSDesc(id_ps2);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+ assertEquals("Check POJO creation", id_ps2.getCreatedObjects().length, 1);
+
+ fooProvider2.stop();
+
+ arch_ps1 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps1);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps1.getState() == ComponentInstance.VALID);
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+ assertEquals("Check dependency ref - 2 ", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ psh = getPSDesc(id_ps1);
+ assertEquals("Check POJO creation", id_ps1.getCreatedObjects().length, 1);
+
+ fooProvider1.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ fooProvider2.start();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ arch_ps2 = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ps2);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id_ps2.getState() == ComponentInstance.VALID);
+ psh = getPSDesc(id_ps2);
+ assertTrue("Check instance validity", id_dep.getState() == ComponentInstance.VALID);
+ assertTrue("Check dependency handler validity", dhd.isValid());
+
+ assertEquals("Check dependency ref -3", dhd.getDependencies()[0].getServiceReferences().size(), 1);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ // Check object graph
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ dhd = getDependencyDesc(id_dep);
+ //id_ps1 = ((Architecture) osgiHelper.getRawServiceObject(arch_ps1)).getInstanceDescription();
+ psh = getPSDesc(id_ps2);
+
+ fooProvider2.stop();
+
+ //id_dep = ((Architecture) osgiHelper.getRawServiceObject(arch_dep)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.VALID);
+ dhd = getDependencyDesc(id_dep);
+ assertTrue("Check dependency handler invalidity", dhd.isValid());
+
+ id_dep = null;
+ cs = null;
+ getContext().ungetService(arch_dep);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestListMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestListMultipleDependencies.java
new file mode 100644
index 0000000..c396422
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestListMultipleDependencies.java
@@ -0,0 +1,255 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestListMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleListCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("OptionalListCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedMultipleDependencies.java
new file mode 100644
index 0000000..f88f78c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedMultipleDependencies.java
@@ -0,0 +1,397 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodDelayedMultipleDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefMultipleCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothMultipleCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapMultipleCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dict");
+ instance7 = ipojoHelper.getFactory("MDictMultipleCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance4.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation - 3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 3", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance5.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 3", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation - 3", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation - 3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation - 3", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance6.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 1", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation - 3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation - 3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation - 3", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation - 3", ((Integer) props.get("dictU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ instance7.stop();
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedSimpleDependencies.java
new file mode 100644
index 0000000..7986ac1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodDelayedSimpleDependencies.java
@@ -0,0 +1,286 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodDelayedSimpleDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectCheckServiceProvider").createComponentInstance(i3);
+ instance3.stop();
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefCheckServiceProvider").createComponentInstance(i4);
+ instance4.stop();
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothCheckServiceProvider").createComponentInstance(i5);
+ instance5.stop();
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapCheckServiceProvider").createComponentInstance(i6);
+ instance6.stop();
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("MDictCheckServiceProvider").createComponentInstance(i7);
+ instance7.stop();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testObject() {
+ instance3.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance3.stop();
+ }
+
+ @Test public void testRef() {
+ instance4.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance4.stop();
+ }
+
+ @Test public void testBoth() {
+ instance5.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance5.stop();
+ }
+
+ @Test public void testMap() {
+ instance6.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance6.stop();
+ }
+
+ @Test public void testDict() {
+ instance7.start();
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+
+ instance7.stop();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodMultipleDependencies.java
new file mode 100644
index 0000000..1573a1c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodMultipleDependencies.java
@@ -0,0 +1,512 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodMultipleDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefMultipleCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothMultipleCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapMultipleCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("MDictMultipleCheckServiceProvider").createComponentInstance(i7);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 2);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 1);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 2);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 1);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 2", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 2", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -2", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -2", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -2", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation -2", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check both bind callback invocation - 3", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation - 3", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -3", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -3", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -3", ((Integer) props.get("dictB")).intValue(), 2);
+ assertEquals("check dict unbind callback invocation -3", ((Integer) props.get("dictU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodSimpleDependencies.java
new file mode 100644
index 0000000..30a9dc6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMethodSimpleDependencies.java
@@ -0,0 +1,286 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMethodSimpleDependencies extends Common {
+
+ ComponentInstance instance3, instance4, instance5, instance6, instance7;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("MObjectCheckServiceProvider").createComponentInstance(i3);
+ assertNotNull("check instance 3", instance3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("MRefCheckServiceProvider").createComponentInstance(i4);
+ assertNotNull("check instance 4", instance4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("MBothCheckServiceProvider").createComponentInstance(i5);
+ assertNotNull("check instance 5", instance5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Map");
+ instance6 = ipojoHelper.getFactory("MMapCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Dictionary");
+ instance7 = ipojoHelper.getFactory("MDictCheckServiceProvider").createComponentInstance(i7);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ fooProvider.dispose();
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ fooProvider = null;
+ }
+
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestModifyDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestModifyDependencies.java
new file mode 100644
index 0000000..ef5c093
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestModifyDependencies.java
@@ -0,0 +1,411 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestModifyDependencies extends Common {
+
+ ComponentInstance instance2, instance3, instance4, instance5, instance7, instance8;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-Updatable").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidModifyCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectModifyCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefModifyCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothModifyCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Map");
+ instance7 = ipojoHelper.getFactory("MapModifyCheckServiceProvider").createComponentInstance(i7);
+
+ Properties i8 = new Properties();
+ i8.put("instance.name", "Dictionary");
+ instance8 = ipojoHelper.getFactory("DictModifyCheckServiceProvider").createComponentInstance(i8);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance7.dispose();
+ instance8.dispose();
+ fooProvider.dispose();
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance7 = null;
+ instance8 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ Object o = osgiHelper.getRawServiceObject(cs_ref);
+ CheckService cs = (CheckService) o;
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1 (" + ((Integer) props.get("voidB")).intValue() + ")", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check modify -1", ((Integer) props.get("modified")).intValue(), 1); // Already called inside the method
+
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1.1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1.1 (" + ((Integer) props.get("voidB")).intValue() + ")", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1.1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1.1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1.1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1.1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1.1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1.1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1.1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3); // 1 (first foo) + 1 (our foo) + 1 (check foo)
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check modify -1 (" + ((Integer) props.get("modified")).intValue() + ")", ((Integer) props.get("modified")).intValue(), 1);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3);
+
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check modify -1 (" + ((Integer) props.get("modified")).intValue() + ")", ((Integer) props.get("modified")).intValue(), 1);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check modify -1 (" + ((Integer) props.get("modified")).intValue() + ")", ((Integer) props.get("modified")).intValue(), 1);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+ }
+
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("check modify -1 (" + ((Integer) props.get("modified")).intValue() + ")", ((Integer) props.get("modified")).intValue(), 1);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+ assertEquals("check modify -1 (" + ((Integer) props.get("modified")).intValue() + ")", ((Integer) props.get("modified")).intValue(), 1);
+
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProvider.getInstanceName());
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+
+ fs.foo(); // Update
+
+ props = cs.getProps();
+ //Check properties
+ assertEquals("check modify -1.1", ((Integer) props.get("modified")).intValue(), 3);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ fs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMultipleDependencies.java
new file mode 100644
index 0000000..d0bdd21
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestMultipleDependencies.java
@@ -0,0 +1,389 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name","FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name","FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name","Simple");
+ instance1 = ipojoHelper.getFactory("SimpleMultipleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name","Void");
+ instance2 = ipojoHelper.getFactory("VoidMultipleCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name","Object");
+ instance3 = ipojoHelper.getFactory("ObjectMultipleCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name","Ref");
+ instance4 = ipojoHelper.getFactory("RefMultipleCheckServiceProvider").createComponentInstance(i4);
+ } catch(Exception e) { fail(e.getMessage()); }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 2);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 1);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 2);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 1);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean)props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer)props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer)props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer)props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer)props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long)props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double)props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean)props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer)props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer)props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer)props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer)props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer)props.get("refB")).intValue(), 2);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer)props.get("refU")).intValue(), 1);
+ assertEquals("Check FS invocation (int) - 3", ((Integer)props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long)props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double)props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestNonProxiedNotInterfaceDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestNonProxiedNotInterfaceDependencies.java
new file mode 100644
index 0000000..7d4ec99
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestNonProxiedNotInterfaceDependencies.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.dependencies;
+
+import junit.framework.Assert;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.AbstractMap;
+import java.util.HashMap;
+
+public class TestNonProxiedNotInterfaceDependencies extends Common {
+
+ InstanceManager instance1;
+ ComponentInstance fooProvider;
+
+ ServiceRegistration reg, reg2;
+
+ @Before
+ public void setUp() {
+ reg = bc.registerService(String.class.getName(), "ahahah", null);
+ reg2 = bc.registerService(AbstractMap.class.getName(), new HashMap(), null);
+
+ }
+
+ @After
+ public void tearDown() {
+ if (reg != null) {
+ reg.unregister();
+ }
+ if (reg2 != null) {
+ reg2.unregister();
+ }
+ }
+
+ @Test
+ public void testInstanceCreation() {
+ instance1 = (InstanceManager) ipojoHelper
+ .createComponentInstance("org.apache.felix.ipojo.runtime.core.test.components.proxy.CheckServiceUsingStringService");
+ Assert.assertTrue(instance1.getState() == ComponentInstance.VALID);
+ Assert.assertTrue(((CheckService) instance1.getPojoObject()).check());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSetMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSetMultipleDependencies.java
new file mode 100644
index 0000000..195065d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSetMultipleDependencies.java
@@ -0,0 +1,255 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSetMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleSetCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("OptionalSetCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSimpleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSimpleDependencies.java
new file mode 100644
index 0000000..b783fa6
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestSimpleDependencies.java
@@ -0,0 +1,422 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.Stability;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSimpleDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4, instance5, instance6, instance7, instance8;
+ ComponentInstance fooProvider;
+
+ @Before
+ public void setUp() {
+ Stability.waitForStability(getContext());
+ System.gc();
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ fooProvider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Void");
+ instance2 = ipojoHelper.getFactory("VoidCheckServiceProvider").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Object");
+ instance3 = ipojoHelper.getFactory("ObjectCheckServiceProvider").createComponentInstance(i3);
+
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Ref");
+ instance4 = ipojoHelper.getFactory("RefCheckServiceProvider").createComponentInstance(i4);
+
+ Properties i5 = new Properties();
+ i5.put("instance.name", "Both");
+ instance5 = ipojoHelper.getFactory("BothCheckServiceProvider").createComponentInstance(i5);
+
+ Properties i6 = new Properties();
+ i6.put("instance.name", "Double");
+ instance6 = ipojoHelper.getFactory("DoubleCheckServiceProvider").createComponentInstance(i6);
+
+ Properties i7 = new Properties();
+ i7.put("instance.name", "Map");
+ instance7 = ipojoHelper.getFactory("MapCheckServiceProvider").createComponentInstance(i7);
+
+ Properties i8 = new Properties();
+ i8.put("instance.name", "Dictionary");
+ instance8 = ipojoHelper.getFactory("DictCheckServiceProvider").createComponentInstance(i8);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ instance5.dispose();
+ instance6.dispose();
+ instance7.dispose();
+ instance8.dispose();
+ fooProvider.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ instance5 = null;
+ instance6 = null;
+ instance7 = null;
+ instance8 = null;
+ fooProvider = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertTrue("check CheckService invocation", cs.check());
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testVoid() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ Object o = osgiHelper.getRawServiceObject(cs_ref);
+ CheckService cs = (CheckService) o;
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1 (" + ((Integer) props.get("voidB")).intValue() + ")", ((Integer) props.get("voidB")).intValue(), 1);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testObject() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testRef() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 1);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testBoth() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance5.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 1);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDouble() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance6.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ assertNotNull("Check cs", cs);
+ cs.check();
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 1);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testMap() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance7.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 1);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 0);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testDict() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance8.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation -1", ((Boolean) props.get("result")).booleanValue());
+ assertEquals("check void bind invocation -1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation -1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation -1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation -1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation -1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation -1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("check both bind callback invocation -1", ((Integer) props.get("bothB")).intValue(), 0);
+ assertEquals("check both unbind callback invocation -1", ((Integer) props.get("bothU")).intValue(), 0);
+ assertEquals("check map bind callback invocation -1", ((Integer) props.get("mapB")).intValue(), 0);
+ assertEquals("check map unbind callback invocation -1", ((Integer) props.get("mapU")).intValue(), 0);
+ assertEquals("check dict bind callback invocation -1", ((Integer) props.get("dictB")).intValue(), 1);
+ assertEquals("check dict unbind callback invocation -1", ((Integer) props.get("dictU")).intValue(), 0);
+
+ fooProvider.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestVectorMultipleDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestVectorMultipleDependencies.java
new file mode 100644
index 0000000..fadcaa8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/TestVectorMultipleDependencies.java
@@ -0,0 +1,255 @@
+/*
+ * 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.test.dependencies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestVectorMultipleDependencies extends Common {
+
+ ComponentInstance instance1, instance2;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov2);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Simple");
+ instance1 = ipojoHelper.getFactory("SimpleVectorCheckServiceProvider").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Optional");
+ instance2 = ipojoHelper.getFactory("OptionalVectorCheckServiceProvider").createComponentInstance(i2);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test public void testSimple() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test public void testOptional() {
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ Properties props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 0", ((Boolean) props.get("result")).booleanValue()); // False : no provider
+ assertEquals("check void bind invocation - 0", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 0", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 0", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 0", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 0", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 0", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 0", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 0", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 0", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ fooProvider1.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 1", ((Boolean) props.get("result")).booleanValue()); // True, a provider is here
+ assertEquals("check void bind invocation - 1", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 1", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 1", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 1", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 1", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 1", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 1", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 1", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 1", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.start();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 2", ((Boolean) props.get("result")).booleanValue()); // True, two providers are here
+ assertEquals("check void bind invocation - 2", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 2", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 2", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 2", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 2", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 2", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 2", ((Integer) props.get("int")).intValue(), 2);
+ assertEquals("Check FS invocation (long) - 2", ((Long) props.get("long")).longValue(), 2);
+ assertEquals("Check FS invocation (double) - 2", ((Double) props.get("double")).doubleValue(), 2.0, 0);
+
+ fooProvider1.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertTrue("check CheckService invocation - 3", ((Boolean) props.get("result")).booleanValue()); // True, it still one provider.
+ assertEquals("check void bind invocation - 3", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 3", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 3", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 3", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 3", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 3", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 3", ((Integer) props.get("int")).intValue(), 1);
+ assertEquals("Check FS invocation (long) - 3", ((Long) props.get("long")).longValue(), 1);
+ assertEquals("Check FS invocation (double) - 3", ((Double) props.get("double")).doubleValue(), 1.0, 0);
+
+ fooProvider2.stop();
+
+ id = ((Architecture) osgiHelper.getRawServiceObject(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+
+ cs = (CheckService) osgiHelper.getRawServiceObject(cs_ref);
+ props = cs.getProps();
+ //Check properties
+ assertFalse("check CheckService invocation - 4", ((Boolean) props.get("result")).booleanValue()); // False, no more provider.
+ assertEquals("check void bind invocation - 4", ((Integer) props.get("voidB")).intValue(), 0);
+ assertEquals("check void unbind callback invocation - 4", ((Integer) props.get("voidU")).intValue(), 0);
+ assertEquals("check object bind callback invocation - 4", ((Integer) props.get("objectB")).intValue(), 0);
+ assertEquals("check object unbind callback invocation - 4", ((Integer) props.get("objectU")).intValue(), 0);
+ assertEquals("check ref bind callback invocation - 4", ((Integer) props.get("refB")).intValue(), 0);
+ assertEquals("check ref unbind callback invocation - 4", ((Integer) props.get("refU")).intValue(), 0);
+ assertEquals("Check FS invocation (int) - 4", ((Integer) props.get("int")).intValue(), 0);
+ assertEquals("Check FS invocation (long) - 4", ((Long) props.get("long")).longValue(), 0);
+ assertEquals("Check FS invocation (double) - 4", ((Double) props.get("double")).doubleValue(), 0.0, 0);
+
+ id = null;
+ cs = null;
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFilters.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFilters.java
new file mode 100644
index 0000000..50b504f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFilters.java
@@ -0,0 +1,200 @@
+/*
+ * 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.test.dependencies.context;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Check the contextual filters using:
+ * - a system properties.
+ * - instance configuration (and reconfiguration)
+ */
+public class TestContextualFilters extends Common {
+
+ @Before
+ public void setup() {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.Provider1");
+
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.Provider2");
+ }
+
+ @After
+ public void tearDown() {
+ System.clearProperty("env.id");
+ }
+
+ @Test
+ public void testContextualFilterWithSystemProperty() {
+ // Set the system property.
+ System.setProperty("env.id", "2");
+
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${env.id})");
+ configuration.put("requires.filters", filters);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=2)", dependency.getFilter());
+ }
+
+ @Test
+ public void testContextualFilterWithUnsetSystemProperty() {
+ // Just to be sure.
+ System.clearProperty("env.id");
+
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${env.id})");
+ configuration.put("requires.filters", filters);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=${env.id})", dependency.getFilter());
+ }
+
+ @Test
+ public void testContextualFilterWithInstanceProperty() {
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${instance.id})");
+ configuration.put("requires.filters", filters);
+ configuration.put("instance.id", 2);
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=2)", dependency.getFilter());
+ }
+
+ /**
+ * This test check filter set using instance properties.
+ * However the instance is reconfigured a couple of times to illustrate the different case:
+ * - unset property
+ * - property updated
+ * - reconfiguration that does not impact the filter
+ */
+ @Test
+ public void testContextualFilterAndInstanceReconfiguration() {
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${instance.id})");
+ configuration.put("requires.filters", filters);
+ configuration.put("instance.id", 2);
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=2)", dependency.getFilter());
+
+ // Reconfigure the instance.
+ Properties newProps = new Properties();
+ newProps.put("instance.id", "3");
+ instance.reconfigure(newProps);
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+ desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ dependency = desc.getDependencies()[0];
+ assertEquals("(id=3)", dependency.getFilter());
+
+ // Another reconfiguration (that does not affect the filters)
+ newProps = new Properties();
+ newProps.put("instance.id", "3");
+ newProps.put("stuff", "stuff");
+ instance.reconfigure(newProps);
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+ desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ dependency = desc.getDependencies()[0];
+ assertEquals("(id=3)", dependency.getFilter());
+
+ // Yet another reconfiguration, un-setting instance.id
+ newProps = new Properties();
+ newProps.put("stuff", "stuff");
+ instance.reconfigure(newProps);
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+ desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ dependency = desc.getDependencies()[0];
+ assertEquals("(id=${instance.id})", dependency.getFilter());
+
+ // Finally another reconfiguration to build a fulfilled filter
+ newProps = new Properties();
+ newProps.put("instance.id", "1");
+ newProps.put("stuff", "stuff");
+ instance.reconfigure(newProps);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ dependency = desc.getDependencies()[0];
+ assertEquals("(id=1)", dependency.getFilter());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFiltersAndExternalSources.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFiltersAndExternalSources.java
new file mode 100644
index 0000000..bcc3fbc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/context/TestContextualFiltersAndExternalSources.java
@@ -0,0 +1,208 @@
+/*
+ * 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.test.dependencies.context;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Check the contextual filters using external sources
+ */
+public class TestContextualFiltersAndExternalSources extends Common {
+
+ private ServiceRegistration registration;
+ private ServiceRegistration registration2;
+
+ @Before
+ public void setup() {
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.Provider1");
+
+ ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.Provider2");
+ }
+
+ @After
+ public void tearDown() {
+ if (registration != null) {
+ registration.unregister();
+ registration = null;
+ }
+
+ if (registration2 != null) {
+ registration2.unregister();
+ registration2 = null;
+ }
+
+ }
+
+ @Test
+ public void testContextualFilterUsingOneSource() {
+ MyContextSource source = new MyContextSource();
+ source.set("source.id", 2);
+ registration = context.registerService(ContextSource.class.getName(),
+ source, null);
+
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${source.id})");
+ configuration.put("requires.filters", filters);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=2)", dependency.getFilter());
+ }
+
+ @Test
+ public void testContextualFilterUsingOneSourceAppearingLater() {
+ MyContextSource source = new MyContextSource();
+ source.set("source.id", 2);
+
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${source.id})");
+ configuration.put("requires.filters", filters);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=${source.id})", dependency.getFilter());
+
+ registration = context.registerService(ContextSource.class.getName(),
+ source, null);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ desc = (DependencyHandlerDescription) instance.getInstanceDescription().getHandlerDescription("org.apache.felix" +
+ ".ipojo:requires");
+
+ // Only one dependency.
+ dependency = desc.getDependencies()[0];
+ assertEquals("(id=2)", dependency.getFilter());
+ }
+
+ @Test
+ public void testContextualFilterUsingOneSourceWithReconfiguration() {
+ MyContextSource source = new MyContextSource();
+ source.set("source.id", 2);
+ registration = context.registerService(ContextSource.class.getName(),
+ source, null);
+
+ Properties configuration = new Properties();
+ Properties filters = new Properties();
+ filters.put("foo", "(id=${source.id})");
+ configuration.put("requires.filters", filters);
+ ComponentInstance instance = ipojoHelper.createComponentInstance("org.apache.felix.ipojo.runtime.core.test" +
+ ".components.context.ContextualFilterConsumer", configuration);
+
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+
+ // Set id to 3 => INVALID
+ source.set("source.id", 3);
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+
+ // Set id to null
+ source.set("source.id", null);
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) instance.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:requires");
+ DependencyDescription dependency = desc.getDependencies()[0];
+ assertEquals("(id=${source.id})", dependency.getFilter());
+
+ // Register a new source.
+ MyContextSource source2 = new MyContextSource();
+ source2.set("source.id", 2);
+ registration2 = context.registerService(ContextSource.class.getName(),
+ source2, null);
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+
+ // This new source disappear
+ registration2.unregister();
+ registration2 = null;
+
+ assertTrue(instance.getState() == ComponentInstance.INVALID);
+
+ source.set("source.id", 1);
+ assertTrue(instance.getState() == ComponentInstance.VALID);
+ }
+
+ private class MyContextSource implements ContextSource {
+
+ List<ContextListener> listeners = new ArrayList<ContextListener>();
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+
+ void set(String key, Object value) {
+ if (value == null) {
+ properties.remove(key);
+ } else {
+ properties.put(key, value);
+ }
+ for (ContextListener cl : listeners) {
+ cl.update(this, key, value);
+ }
+ }
+
+ @Override
+ public Object getProperty(String property) {
+ return properties.get(property);
+ }
+
+ @Override
+ public Dictionary getContext() {
+ return properties;
+ }
+
+ @Override
+ public void registerContextListener(ContextListener listener, String[] properties) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void unregisterContextListener(ContextListener listener) {
+ listeners.remove(listener);
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/error/TestNPEInBindMethod.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/error/TestNPEInBindMethod.java
new file mode 100644
index 0000000..e518d68
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/error/TestNPEInBindMethod.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.dependencies.error;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+/**
+ * Checks what happens when we access a service throwing a NPE in its bind method.
+ */
+public class TestNPEInBindMethod extends Common {
+
+
+ @Test
+ public void testNPEInBindMethod() throws MissingHandlerException, UnacceptableConfiguration, ConfigurationException {
+ Factory factory = ipojoHelper.getFactory("org.apache.felix.ipojo.runtime.core.test.components.error" +
+ ".NullPointerExceptionBinder");
+
+ assertNotNull(factory);
+
+ ComponentInstance instance = factory.createComponentInstance(null);
+ assertEquals(instance.getState(), ComponentInstance.STOPPED);
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestFromDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestFromDependencies.java
new file mode 100644
index 0000000..a93c493
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestFromDependencies.java
@@ -0,0 +1,320 @@
+/*
+ * 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.test.dependencies.filter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestFromDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3, instance4;
+ ComponentInstance providerA, providerB, providerC, providerD;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "A");
+ providerA = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ providerA.stop();
+
+ Properties prov2 = new Properties();
+ prov2.put("instance.name", "B");
+ providerB = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov2);
+ providerB.stop();
+
+ Properties prov3 = new Properties();
+ prov3.put("service.pid", "A");
+ providerC = ipojoHelper.getFactory("SimplePIDCheckServiceProvider").createComponentInstance(prov3);
+ providerC.stop();
+
+ Properties prov4 = new Properties();
+ prov4.put("service.pid", "D");
+ prov4.put("instance.name", "D");
+ providerD = ipojoHelper.getFactory("SimplePIDCheckServiceProvider").createComponentInstance(prov4);
+ providerD.stop();
+
+ // Uses the component type from value
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Subscriber1");
+ instance1 = ipojoHelper.getFactory("SimpleFromCheckServiceSubscriber").createComponentInstance(i1);
+
+ // Uses the instance configuration from value
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Subscriber2");
+ Properties ii2 = new Properties();
+ ii2.put("id1", "B");
+ i2.put("requires.from", ii2);
+ instance2 = ipojoHelper.getFactory("SimpleFromCheckServiceSubscriber").createComponentInstance(i2);
+
+ // Uses the instance configuration from value (*)
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Subscriber3");
+ Properties ii3 = new Properties();
+ ii3.put("id1", "*");
+ i3.put("requires.from", ii3);
+ instance3 = ipojoHelper.getFactory("SimpleFromCheckServiceSubscriber").createComponentInstance(i3);
+
+ // Uses the instance configuration from value, merge filter and from
+ Properties i4 = new Properties();
+ i4.put("instance.name", "Subscriber4");
+ Properties ii4 = new Properties();
+ ii4.put("id1", "D");
+ i4.put("requires.from", ii4);
+ Properties iii4 = new Properties();
+ iii4.put("id1", "(service.pid=D)");
+ i4.put("requires.filters", iii4);
+ instance4 = ipojoHelper.getFactory("SimpleFromCheckServiceSubscriber").createComponentInstance(i4);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ instance4.dispose();
+ providerA.dispose();
+ providerB.dispose();
+ providerC.dispose();
+ providerD.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ instance4 = null;
+ providerA = null;
+ providerB = null;
+ providerC = null;
+ providerD = null;
+ }
+
+
+ @Test
+ public void testFromInstanceName() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ providerA.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ providerA.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ providerA.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+
+ providerA.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ providerB.stop();
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testFromPID() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ providerC.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ providerC.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ providerC.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ providerC.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ providerB.stop();
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testFromInstanceNameInstanceConfiguration() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ providerA.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ providerB.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ providerB.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ providerA.stop();
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testFromInstanceNameStar() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ providerA.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 0", id.getState() == ComponentInstance.VALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ providerB.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.VALID);
+
+ providerA.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.INVALID);
+
+ providerB.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.VALID);
+
+ id = null;
+ providerB.stop();
+ getContext().ungetService(arch_ref);
+ }
+
+ @Test
+ public void testFromAndFilter() {
+ instance4.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance4.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ providerA.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ providerD.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ providerD.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ providerD.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ providerD.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ providerA.stop();
+ getContext().ungetService(arch_ref);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestMultipleFilterDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestMultipleFilterDependencies.java
new file mode 100644
index 0000000..c6bb38a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestMultipleFilterDependencies.java
@@ -0,0 +1,595 @@
+/*
+ * 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.test.dependencies.filter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class TestMultipleFilterDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ prov = new Properties();
+ prov.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Subscriber1");
+ instance1 = ipojoHelper.getFactory("MultipleFilterCheckServiceSubscriber").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Subscriber2");
+ Properties ii2 = new Properties();
+ ii2.put("id2", "(toto=A)");
+ i2.put("requires.filters", ii2);
+ instance2 = ipojoHelper.getFactory("MultipleFilterCheckServiceSubscriber2").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Subscriber3");
+ Properties ii3 = new Properties();
+ ii3.put("id1", "(toto=A)");
+ i3.put("requires.filters", ii3);
+ instance3 = ipojoHelper.getFactory("MultipleFilterCheckServiceSubscriber").createComponentInstance(i3);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testMultipleNotMatch() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ fooProvider2.start();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 7", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider2.start();
+ cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 9", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleMatch() {
+
+ fooProvider1.start();
+ fooProvider2.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider2.start();
+ cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleNotMatchInstance() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.start();
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 7", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 9", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleMatchInstance() {
+
+ fooProvider1.start();
+ fooProvider2.start();
+ instance3.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleNotMatchInstanceWithoutFilter() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.start();
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 7", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 9", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleMatchInstanceWithoutFilter() {
+ fooProvider1.start();
+ fooProvider2.start();
+ instance2.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalMultipleFilterDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalMultipleFilterDependencies.java
new file mode 100644
index 0000000..9bb6768
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalMultipleFilterDependencies.java
@@ -0,0 +1,621 @@
+/*
+ * 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.test.dependencies.filter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class TestOptionalMultipleFilterDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ prov = new Properties();
+ prov.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Subscriber1");
+ instance1 = ipojoHelper.getFactory("OptionalMultipleFilterCheckServiceSubscriber").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Subscriber2");
+ Properties ii2 = new Properties();
+ ii2.put("id2", "(toto=A)");
+ i2.put("requires.filters", ii2);
+ instance2 = ipojoHelper.getFactory("OptionalMultipleFilterCheckServiceSubscriber2").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Subscriber3");
+ Properties ii3 = new Properties();
+ ii3.put("id1", "(toto=A)");
+ i3.put("requires.filters", ii3);
+ instance3 = ipojoHelper.getFactory("OptionalMultipleFilterCheckServiceSubscriber").createComponentInstance(i3);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testMultipleNotMatch() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 7", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 7", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 7", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 9", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 9", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 9", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+
+ @Test
+ public void testMultipleMatch() {
+
+ fooProvider1.start();
+ fooProvider2.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleNotMatchInstance() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ fooProvider2.start();
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 7", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 7", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 7", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 9", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 9", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 9", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleMatchInstance() {
+
+ fooProvider1.start();
+ fooProvider2.start();
+ instance3.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleNotMatchInstanceWithoutFilter() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ fooProvider2.start();
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+ CheckService cs2 = (CheckService) getContext().getService(cs_ref2);
+ // change the value of the property toto
+ cs2.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+
+ // change the value of the property toto
+ cs2.check();
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 6", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 7", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 7", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 7", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 8", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 9", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 9", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 9", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ id = null;
+ cs = null;
+ cs2 = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+ @Test
+ public void testMultipleMatchInstanceWithoutFilter() {
+
+
+ fooProvider1.start();
+ fooProvider2.start();
+ instance2.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+
+ ServiceReference cs_ref2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref2);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 1", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 2", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ fooProvider2.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Array size - 3", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(0)));
+
+ fooProvider2.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertTrue("Check Array size - 4", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(1)));
+
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(2)));
+ assertTrue("Check Array size - 5", ((Integer) cs_instance.getProps().get("Size")).equals(new Integer(2)));
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ getContext().ungetService(cs_ref2);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalSimpleFilterDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalSimpleFilterDependencies.java
new file mode 100644
index 0000000..6593254
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestOptionalSimpleFilterDependencies.java
@@ -0,0 +1,591 @@
+/*
+ * 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.test.dependencies.filter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestOptionalSimpleFilterDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ prov = new Properties();
+ prov.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Subscriber1");
+ instance1 = ipojoHelper.getFactory("OptionalSimpleFilterCheckServiceSubscriber").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Subscriber2");
+ Properties ii2 = new Properties();
+ ii2.put("id2", "(toto=A)");
+ i2.put("requires.filters", ii2);
+ instance2 = ipojoHelper.getFactory("OptionalSimpleFilterCheckServiceSubscriber2").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Subscriber3");
+ Properties ii3 = new Properties();
+ ii3.put("id1", "(toto=A)");
+ i3.put("requires.filters", ii3);
+ instance3 = ipojoHelper.getFactory("OptionalSimpleFilterCheckServiceSubscriber").createComponentInstance(i3);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testSimpleNotMatch() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start(); // Registered with toto = A
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID); // Optional
+ assertTrue("Check service Binding - 7.0 (" + (Integer) cs_instance.getProps().get("Bind") + ")", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check(); // Update toto to B
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3.1", id.getState() == ComponentInstance.VALID);
+
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+ assertTrue("Check service Binding - 7.1 (" + (Integer) cs_instance.getProps().get("Bind") + ")", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 7", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 8", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatch() {
+
+ fooProvider1.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check(); // Update toto to B
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5.1", id.getState() == ComponentInstance.VALID);
+
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleNotMatchInstance() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 7", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 7", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 7", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 8", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatchInstance() {
+
+ fooProvider1.start();
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleNotMatchInstanceWithoutFilter() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 7", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 7", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 7", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 8", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 8", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 8", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatchInstanceWithoutFilter() {
+
+ fooProvider1.start();
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 1", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 1", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 2", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 2", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 3", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 3", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 4", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 4", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 4", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 5", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 5", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(1)));
+ assertFalse("Check Nullable - 5", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 6", id.getState() == ComponentInstance.VALID);
+ assertTrue("Check service invocation", cs_instance.check());
+ assertTrue("Check service Binding - 6", ((Integer) cs_instance.getProps().get("Bind")).equals(new Integer(0)));
+ assertTrue("Check Nullable - 6", ((Boolean) cs_instance.getProps().get("Nullable")).booleanValue());
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestSimpleFilterDependencies.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestSimpleFilterDependencies.java
new file mode 100644
index 0000000..bc3ad30
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/filter/TestSimpleFilterDependencies.java
@@ -0,0 +1,526 @@
+/*
+ * 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.test.dependencies.filter;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+public class TestSimpleFilterDependencies extends Common {
+
+ ComponentInstance instance1, instance2, instance3;
+ ComponentInstance fooProvider1, fooProvider2;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider1");
+ fooProvider1 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider1.stop();
+
+ prov = new Properties();
+ prov.put("instance.name", "FooProvider2");
+ fooProvider2 = ipojoHelper.getFactory("SimpleFilterCheckServiceProvider").createComponentInstance(prov);
+ fooProvider2.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Subscriber1");
+ instance1 = ipojoHelper.getFactory("SimpleFilterCheckServiceSubscriber").createComponentInstance(i1);
+
+ Properties i2 = new Properties();
+ i2.put("instance.name", "Subscriber2");
+ Properties ii2 = new Properties();
+ ii2.put("id2", "(toto=A)");
+ i2.put("requires.filters", ii2);
+ instance2 = ipojoHelper.getFactory("SimpleFilterCheckServiceSubscriber2").createComponentInstance(i2);
+
+ Properties i3 = new Properties();
+ i3.put("instance.name", "Subscriber3");
+ Properties ii3 = new Properties();
+ ii3.put("id1", "(toto=A)");
+ i3.put("requires.filters", ii3);
+ instance3 = ipojoHelper.getFactory("SimpleFilterCheckServiceSubscriber").createComponentInstance(i3);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+
+ }
+
+ @After
+ public void tearDown() {
+ instance1.dispose();
+ instance2.dispose();
+ instance3.dispose();
+ fooProvider1.dispose();
+ fooProvider2.dispose();
+ instance1 = null;
+ instance2 = null;
+ instance3 = null;
+ fooProvider1 = null;
+ fooProvider2 = null;
+ }
+
+ @Test
+ public void testSimpleNotMatch() {
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+
+ assertTrue("Check instance invalidity - 4.1", id.getState() == ComponentInstance.INVALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ cs.check();
+
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatch() {
+
+ fooProvider1.start();
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ instance1.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4.1", id.getState() == ComponentInstance.INVALID);
+
+ cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ cs = (CheckService) getContext().getService(cs_ref);
+ cs.check();
+
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleNotMatchInstance() {
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatchInstance() {
+
+ fooProvider1.start();
+ instance3.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance3.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleNotMatchInstanceWithoutFilter() {
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 4", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 5", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+ @Test
+ public void testSimpleMatchInstanceWithoutFilter() {
+
+ fooProvider1.start();
+ instance2.start();
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check architecture availability", arch_ref);
+ InstanceDescription id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 1", id.getState() == ComponentInstance.VALID);
+
+ ServiceReference cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ CheckService cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("Check service invocation", cs_instance.check());
+
+ ServiceReference cs_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), fooProvider1.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_ref);
+ CheckService cs = (CheckService) getContext().getService(cs_ref);
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 1", id.getState() == ComponentInstance.INVALID);
+
+ // change the value of the property toto
+ cs.check();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 2", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 2", id.getState() == ComponentInstance.INVALID);
+
+ fooProvider1.start();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance validity - 3", id.getState() == ComponentInstance.VALID);
+
+ cs_instance_ref = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), instance2.getInstanceName());
+ assertNotNull("Check CheckService availability", cs_instance_ref);
+ cs_instance = (CheckService) getContext().getService(cs_instance_ref);
+ assertTrue("check CheckService invocation", cs_instance.check());
+
+ fooProvider1.stop();
+
+ id = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();
+ assertTrue("Check instance invalidity - 3", id.getState() == ComponentInstance.INVALID);
+
+ id = null;
+ cs = null;
+ cs_instance = null;
+ getContext().ungetService(cs_instance_ref);
+ getContext().ungetService(arch_ref);
+ getContext().ungetService(cs_ref);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java
new file mode 100644
index 0000000..630058d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java
@@ -0,0 +1,108 @@
+/*
+ * 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.test.dependencies.identification;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.annotations.HandlerDeclaration;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyCallback;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class TestDependencyIdDetection extends Common {
+ String factory = "org.apache.felix.ipojo.runtime.core.test.components.identification.ComponentWithCustomMethods";
+
+ @Test
+ public void testSetAndUnSetMethods() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance(factory);
+ DependencyHandlerDescription dh = (DependencyHandlerDescription) instance.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:requires");
+
+ DependencyDescription dd = findDependencyById(dh, "MyOtherService");
+ assertThat(dd).isNotNull();
+
+ DependencyCallback[] callbacks = dd.getDependency().getDependencyCallbacks();
+ assertThat(callbacks).isNotNull();
+
+ DependencyCallback bind = getBindCallback(callbacks);
+ DependencyCallback unbind = getUnbindCallback(callbacks);
+
+ assertThat(bind).isNotNull();
+ assertThat(unbind).isNotNull();
+
+ assertThat(bind.getMethodName()).isEqualTo("setMyOtherService");
+ assertThat(unbind.getMethodName()).isEqualTo("unsetMyOtherService");
+ }
+
+ @Test
+ public void testAddAndRemoveMethods() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance(factory);
+ DependencyHandlerDescription dh = (DependencyHandlerDescription) instance.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:requires");
+
+ DependencyDescription dd = findDependencyById(dh, "MyService");
+ assertThat(dd).isNotNull();
+
+ DependencyCallback[] callbacks = dd.getDependency().getDependencyCallbacks();
+ assertThat(callbacks).isNotNull();
+
+ DependencyCallback bind = getBindCallback(callbacks);
+ DependencyCallback unbind = getUnbindCallback(callbacks);
+
+ assertThat(bind).isNotNull();
+ assertThat(unbind).isNotNull();
+
+ assertThat(bind.getMethodName()).isEqualTo("addMyService");
+ assertThat(unbind.getMethodName()).isEqualTo("removeMyService");
+ }
+
+ private DependencyCallback getBindCallback(DependencyCallback[] callbacks) {
+ for (DependencyCallback callback : callbacks) {
+ if (callback.getMethodType() == DependencyCallback.BIND) {
+ return callback;
+ }
+ }
+ return null;
+ }
+
+ private DependencyCallback getUnbindCallback(DependencyCallback[] callbacks) {
+ for (DependencyCallback callback : callbacks) {
+ if (callback.getMethodType() == DependencyCallback.UNBIND) {
+ return callback;
+ }
+ }
+ return null;
+ }
+
+ private DependencyDescription findDependencyById(DependencyHandlerDescription dh, String id) {
+ for (DependencyDescription dd : dh.getDependencies()) {
+ if (dd.getId().equals(id)) {
+ return dd;
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/inner/TestInnerProxyMix.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/inner/TestInnerProxyMix.java
new file mode 100644
index 0000000..a91735c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/inner/TestInnerProxyMix.java
@@ -0,0 +1,85 @@
+/*
+ * 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.test.dependencies.inner;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.components.inner.C1;
+import org.apache.felix.ipojo.runtime.core.test.components.inner.C2;
+import org.apache.felix.ipojo.runtime.core.test.components.inner.C3;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestInnerProxyMix extends Common {
+
+ public static String C1 = "org.apache.felix.ipojo.runtime.core.test.components.inner.C1";
+ public static String C2 = "org.apache.felix.ipojo.runtime.core.test.components.inner.C2";
+ public static String C3 = "org.apache.felix.ipojo.runtime.core.test.components.inner.C3";
+
+ private ComponentInstance instancec1;
+ private ComponentInstance instancec2;
+ private ComponentInstance instancec3;
+
+ @Before
+ public void setUp() {
+ // Create the instances
+ instancec1 = ipojoHelper.createComponentInstance(C1);
+ instancec2 = ipojoHelper.createComponentInstance(C2);
+ instancec3 = ipojoHelper.createComponentInstance(C3);
+ }
+
+ @Test
+ public void testMix() {
+ // Check that everything is OK
+ assertEquals(ComponentInstance.VALID, instancec1.getState());
+ assertEquals(ComponentInstance.VALID, instancec2.getState());
+ assertEquals(ComponentInstance.VALID, instancec3.getState());
+
+ // Call C3
+ C3 svc = (C3) osgiHelper.getServiceObject(C3, null);
+ assertNotNull(svc);
+ assertEquals("called", svc.getFilter().authenticate());
+
+ // So far, all right
+
+ //We stop c1 and c2.
+ instancec1.stop();
+ instancec2.stop();
+
+ assertEquals(ComponentInstance.INVALID, instancec3.getState()); // C2 dependency invalid
+
+ instancec1.start();
+ instancec2.start();
+
+ // Check that everything is OK
+ assertEquals(ComponentInstance.VALID, instancec1.getState());
+ assertEquals(ComponentInstance.VALID, instancec2.getState());
+ assertEquals(ComponentInstance.VALID, instancec3.getState());
+
+ // Call C3
+ svc = (C3) osgiHelper.getServiceObject(C3, null);
+ assertNotNull(svc);
+ assertEquals("called", svc.getFilter().authenticate());
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/leak/ListenerStyleLeakTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/leak/ListenerStyleLeakTest.java
new file mode 100644
index 0000000..fc81b60
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/leak/ListenerStyleLeakTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.test.dependencies.leak;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+import org.apache.felix.ipojo.runtime.core.test.services.LeakingService;
+import org.apache.felix.ipojo.runtime.core.test.services.Listener;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Check the fix of the leak FELIX-4247 Memory leak with ServiceUsage and inner class (Listener style).
+ */
+public class ListenerStyleLeakTest extends Common {
+
+ public static final String DEFAULT_HELLO_SERVICE = "org.apache.felix.ipojo.runtime.core.test.components.leak" +
+ ".DefaultHelloService";
+ public static final String DEFAULT_LEAKING_SERVICE = "org.apache.felix.ipojo.runtime.core.test.components.leak" +
+ ".DefaultLeakingService";
+
+ /**
+ * This test does not use the listener-style.
+ * <ol>
+ * <li>Gets the hello message from the leaking instance using the hello instance</li>
+ * <li>Stops the hello instance</li>
+ * <li>Get the hello message again, must be {@code null}</li>
+ * </ol>
+ *
+ */
+ @Test
+ public void testNormalStyle() {
+
+ ComponentInstance hello = ipojoHelper.createComponentInstance(DEFAULT_HELLO_SERVICE);
+ ComponentInstance leaking = ipojoHelper.createComponentInstance(DEFAULT_LEAKING_SERVICE);
+
+ assertThat(hello.getState()).isEqualTo(ComponentInstance.VALID);
+ assertThat(leaking.getState()).isEqualTo(ComponentInstance.VALID);
+
+ LeakingService service = osgiHelper.waitForService(LeakingService.class,
+ "(instance.name=" + leaking.getInstanceName() + ")", 1000);
+ osgiHelper.waitForService(HelloService.class, "(instance.name=" + hello.getInstanceName() + ")", 1000);
+
+ String result = service.executeListener();
+ assertThat(result).isEqualToIgnoringCase("hello iPOJO");
+
+ hello.stop();
+
+ result = service.executeListener();
+ assertThat(result).isNull();
+ }
+
+ /**
+ * This test do use the listener-style.
+ * <ol>
+ * <li>Gets the listener object provided by the leaking instance</li>
+ * <li>Gets the hello message from this listener. As the hello service is bound,
+ * it relies on the hello instance</li>
+ * <li>Stops the hello instance</li>
+ * <li>Get the hello message again, must be {@code null}</li>
+ * </ol>
+ *
+ */
+ @Test
+ public void testListenerStyle() {
+
+ ComponentInstance hello = ipojoHelper.createComponentInstance(DEFAULT_HELLO_SERVICE);
+ ComponentInstance leaking = ipojoHelper.createComponentInstance(DEFAULT_LEAKING_SERVICE);
+
+ assertThat(hello.getState()).isEqualTo(ComponentInstance.VALID);
+ assertThat(leaking.getState()).isEqualTo(ComponentInstance.VALID);
+
+ LeakingService service = osgiHelper.waitForService(LeakingService.class,
+ "(instance.name=" + leaking.getInstanceName() + ")", 1000);
+ osgiHelper.waitForService(HelloService.class, "(instance.name=" + hello.getInstanceName() + ")", 1000);
+
+ Listener listener = service.getListener();
+ String result = listener.doSomething();
+ assertThat(result).isEqualToIgnoringCase("hello iPOJO");
+
+ hello.stop();
+
+ result = listener.doSomething();
+ assertThat(result).isNull();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml
new file mode 100644
index 0000000..37b4102
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ipojo-core-service-dependency-timeout-test</artifactId>
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.java
new file mode 100644
index 0000000..7f6f979
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.java
@@ -0,0 +1,44 @@
+/*
+ * 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.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService fs;
+
+ public boolean check() {
+ return fs != null && fs.foo();
+ }
+
+ public Properties getProps() {
+ if (fs != null) {
+ return fs.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.java
new file mode 100644
index 0000000..e410197
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.java
@@ -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.felix.ipojo.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class CollectionCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private Collection<FooService> fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ Collection<FooService> col = fs;
+ if (col != null) {
+ for (FooService svc : col) {
+ result = result && svc.foo();
+ }
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ Iterator<FooService> it = fs.iterator();
+ if (it.hasNext()) {
+ FooService svc = it.next();
+ return svc.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.java
new file mode 100644
index 0000000..44ac92f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.java
@@ -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.felix.ipojo.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+
+import java.util.Properties;
+
+public class FooProvider implements FooService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java
new file mode 100644
index 0000000..92fc795
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.dependencies.timeout.components;
+
+
+import java.util.Properties;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+public class MultipleCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService[] fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ FooService[] array = fs;
+ for (int i = 0; array != null && i < array.length; i++) {
+ result = result && array[i].foo();
+ System.out.println("Result : " + result);
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ return fs[0].fooProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.java
new file mode 100644
index 0000000..01f7f79
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.java
@@ -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.felix.ipojo.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Properties;
+
+public class NullableFooProvider implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return -1;
+ }
+
+ public int getInt() {
+ return -1;
+ }
+
+ public long getLong() {
+ return -1;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java
new file mode 100644
index 0000000..af98aca
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.dependencies.timeout.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java
new file mode 100644
index 0000000..9c1550a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.test.dependencies.timeout.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..8c10d12
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml
@@ -0,0 +1,142 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo">
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="CheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.FooProvider"
+ name="FooProvider">
+ <provides/>
+ </component>
+
+ <!-- Dependencies using nullables (scalar dependency only) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullableCheckServiceProvider">
+ <requires field="fs" optional="true"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullableCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+
+ <!-- Dependencies using default implementation (scalar dependency only)-->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="DICheckServiceProvider">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="DICheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"
+ default-implementation="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+
+ <!-- Dependencies using null (nullable = false, scalar dependency only) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullCheckServiceProvider">
+ <requires field="fs" optional="true" nullable="false"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300" nullable="false"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using empty arrays or collections (aggregate dependency only), it's the default policy. -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.MultipleCheckServiceProvider"
+ name="EmptyMultipleCheckServiceProvider">
+ <requires field="fs" optional="true"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="EmptyColCheckServiceProvider">
+ <requires field="fs" optional="true"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.MultipleCheckServiceProvider"
+ name="EmptyMultipleCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="EmptyColCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using exceptions (aggregate and scalar) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="ExceptionCheckServiceProvider">
+ <requires field="fs" optional="true" exception="java.lang.RuntimeException"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="ExceptionCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300" exception="java.lang.RuntimeException"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="ExceptionColCheckServiceProvider">
+ <requires field="fs" optional="true"
+ exception="java.lang.RuntimeException"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="ExceptionColCheckServiceProviderTimeout">
+ <requires field="fs" optional="true"
+ exception="java.lang.RuntimeException"
+ timeout="300"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java
new file mode 100644
index 0000000..bef5281
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java
new file mode 100644
index 0000000..7f8864d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java
@@ -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.felix.ipojo.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import static org.junit.Assert.*;
+
+public class DefaultImplementationTest extends Common {
+
+ @Test
+ public void testDefaultImplementationTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("DICheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ if (TimeUtils.TIME_FACTOR == 1) {
+ fail("A nullable was expected ...");
+ } else {
+ System.err.println("A null was expected, however this test really depends on your CPU and IO speed");
+ return;
+ }
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("DICheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java
new file mode 100644
index 0000000..9b76b7a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.After;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import static org.junit.Assert.*;
+
+@ExamReactorStrategy(PerMethod.class)
+public class DelayTest extends Common {
+
+ private DelayedProvider delayed;
+
+ @After
+ public void tearDown() {
+ if (delayed != null) {
+ delayed.stop();
+ }
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+
+
+ @Test
+ public void testTimeoutWithException() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("ExceptionCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ delayed = new DelayedProvider(provider, 1000);
+ delayed.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ delayed.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+ if (TimeUtils.TIME_FACTOR == 1) {
+ fail("Timeout expected");
+ } else {
+ System.err.println("A timeout was expected, however this test really depends on your CPU and IO speed");
+ }
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyMultipleCheckServiceProviderTimeout",
+ un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java
new file mode 100644
index 0000000..bcc7377
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java
@@ -0,0 +1,74 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+public class DelayedProvider implements Runnable {
+
+
+ public static final long DELAY = 1000;
+ ComponentInstance instance;
+ long delay = DELAY;
+ Thread thread;
+
+ public DelayedProvider(ComponentInstance ci) {
+ instance =ci;
+ }
+
+ public DelayedProvider(ComponentInstance ci, long time) {
+ instance =ci;
+ delay = time;
+ }
+
+ public void start() {
+ thread = new Thread(this);
+ thread.start();
+ }
+
+ public void stop() {
+ if (thread != null) {
+ thread.interrupt();
+ }
+ }
+
+ public void run() {
+ long d = delay;
+ System.out.println("Start sleeping for " + d);
+ long begin = System.currentTimeMillis();
+ try {
+ Thread.sleep(d);
+ long end = System.currentTimeMillis();
+ if (end - begin < d) {
+ // Wait for the remaining time
+ Thread.sleep(d - (end - begin));
+ }
+ } catch (InterruptedException e) {
+ System.out.println("Interrupted ...");
+ return;
+ }
+ System.out.println("Wakeup");
+ thread = null;
+ instance.start();
+ System.out.println(instance.getInstanceName() + " started");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java
new file mode 100755
index 0000000..eaae61c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.After;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import static org.junit.Assert.*;
+
+@ExamReactorStrategy(PerMethod.class)
+public class EmptyTest extends Common {
+
+ private DelayedProvider delayed;
+
+ @After
+ public void tearDown() {
+ if (delayed != null) {
+ delayed.stop();
+ }
+ }
+
+ @Test
+ public void testEmptyArrayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper
+ .createComponentInstance("EmptyMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 1000);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testEmptyCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper
+ .createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ delayed = new DelayedProvider(provider, 400);
+ delayed.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ if (TimeUtils.TIME_FACTOR == 1) {
+ fail("An exception was expected ...");
+ } else {
+ System.err.println("An exception was expected, however this test really depends on your CPU and IO " +
+ "speed");
+ return;
+ }
+ }
+ assertTrue("Check empty array", res);
+
+ delayed.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java
new file mode 100644
index 0000000..a4c97ee
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class NullTest extends Common {
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java
new file mode 100644
index 0000000..ec09aad
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+@ExamReactorStrategy(PerMethod.class)
+public class NullableTest extends Common {
+
+ @Test
+ public void testNullableTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullableCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullableCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java
new file mode 100644
index 0000000..e5ecdcc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.After;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import static org.junit.Assert.*;
+
+public class TimeoutTest extends Common {
+
+ private DelayedProvider delayed;
+
+ @After
+ public void tearDown() {
+ if (delayed != null) {
+ delayed.stop();
+ }
+ }
+
+ @Test
+ public void testDelay() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ assertNull("No FooService", osgiHelper.getServiceReference(FooService.class.getName(), null));
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay (" + (end - begin) + ")", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+
+ @Test
+ public void testTimeoutWithException() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("ExceptionCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ delayed = new DelayedProvider(provider, 1000);
+ delayed.start();
+ cs = (CheckService) osgiHelper.getRawServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ delayed.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ if (TimeUtils.TIME_FACTOR == 1) {
+ fail("An exception was expected ...");
+ } else {
+ System.err.println("An exception was expected, however this test really depends on your CPU and IO " +
+ "speed");
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/pom.xml
new file mode 100644
index 0000000..9cfdfed
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ipojo-core-service-providing-test</artifactId>
+
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
new file mode 100644
index 0000000..91c9f75
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckProviderParentClass.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class CheckProviderParentClass {
+
+ int simpleU = 0;
+ int objectU = 0;
+ int refU = 0;
+ int bothU = 0;
+
+
+ public void bothUnbind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothU++; }
+ }
+
+ public void refUnbind(ServiceReference sr) {
+ if(sr != null) { refU++; }
+ }
+
+ public void objectUnbind(FooService o) {
+ if(o != null && o instanceof FooService) { objectU++; }
+ else {
+ System.err.println("Unbind null : " + o);
+ }
+ }
+
+ public void voidUnbind() {
+ simpleU++;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
new file mode 100644
index 0000000..5abe521
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/CheckServiceProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CheckServiceProvider extends CheckProviderParentClass implements CheckService {
+
+ FooService fs;
+
+ int simpleB = 0;
+ int objectB = 0;
+ int refB = 0;
+ int bothB = 0;
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("voidB", new Integer(simpleB));
+ props.put("objectB", new Integer(objectB));
+ props.put("refB", new Integer(refB));
+ props.put("bothB", new Integer(bothB));
+ props.put("voidU", new Integer(simpleU));
+ props.put("objectU", new Integer(objectU));
+ props.put("refU", new Integer(refU));
+ props.put("bothU", new Integer(bothU));
+ if (fs != null) {
+ props.put("result", new Boolean(fs.foo()));
+ props.put("boolean", new Boolean(fs.getBoolean()));
+ props.put("int", new Integer(fs.getInt()));
+ props.put("long", new Long(fs.getLong()));
+ props.put("double", new Double(fs.getDouble()));
+ if(fs.getObject() != null) { props.put("object", fs.getObject()); }
+ }
+ props.put("static", CheckService.foo);
+ props.put("class", CheckService.class.getName());
+ return props;
+ }
+
+ private void voidBind() {
+ simpleB++;
+ }
+
+ protected void objectBind(FooService o) {
+ if (o == null) {
+ System.err.println("Bind receive null !!! ");
+ return;
+ }
+ if(o != null && o instanceof FooService) { objectB++; }
+ }
+
+ public void refBind(ServiceReference sr) {
+ if(sr != null) { refB++; }
+ }
+
+ public void bothBind(FooService o, ServiceReference sr) {
+ if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
new file mode 100644
index 0000000..c53570b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooBarProviderType1.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return new Properties();
+ }
+
+ public boolean bar() {
+ return true;
+ }
+
+ public Properties getProps() {
+ return new Properties();
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
new file mode 100644
index 0000000..22059a8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderType1.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.BundleContext;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ private int m_bar;
+ private String m_foo;
+
+ private BundleContext m_context;
+
+ private static FooProviderType1 singleton;
+ private static int count = 0;
+
+ private static FooProviderType1 singleton(BundleContext bc) {
+ if (singleton == null) {
+ count++;
+ singleton = new FooProviderType1(bc);
+ }
+ return singleton;
+ }
+
+ public static FooProviderType1 several(BundleContext bc) {
+ count++;
+ return new FooProviderType1(bc);
+ }
+
+ public FooProviderType1(BundleContext bc) {
+ if (bc ==null) {
+ throw new RuntimeException("Injected bundle context null");
+ }
+ m_context = bc;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+ p.put("context", m_context);
+
+ p.put("count", new Integer(count));
+ return p;
+ }
+
+ public void testException() throws Exception {
+ String a = "foobarbaz";
+ throw new Exception("foo"+a);
+ }
+
+ public void testTry() {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ public void testTry2(String s) {
+ String a = "foo";
+ a.charAt(0);
+ }
+
+ private void nexttry(String s) {
+ try {
+ s += "foo";
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ /**
+ * Custom constructor.
+ * @param bar
+ * @param foo
+ * @param bc
+ */
+ public FooProviderType1(int bar, String foo, BundleContext bc) {
+ m_bar = bar;
+ m_foo = foo;
+ m_context = bc;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
new file mode 100644
index 0000000..c52415f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+
+public class FooProviderTypeDyn implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ intProp = 3;
+ boolProp = true;
+ if(strProp.equals("foo")) { strProp = "bar"; }
+ else { strProp = "foo"; }
+ strAProp = new String[] {"foo", "bar", "baz"};
+ intAProp = new int[] {3, 2, 1};
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
new file mode 100644
index 0000000..f1732ba
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderTypeDyn2.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderTypeDyn2 implements FooService {
+
+ private int intProp = 2;
+ private boolean boolProp = true;
+ private String strProp = "foo";
+ private String[] strAProp = new String[] {"foo", "bar"};
+ private int[] intAProp = new int[] {1, 2, 3};
+
+ public boolean foo() {
+ intAProp = null;
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderWithAnonymousClass.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderWithAnonymousClass.java
new file mode 100644
index 0000000..afc8988
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/FooProviderWithAnonymousClass.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderWithAnonymousClass implements FooService {
+
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+
+ public boolean foo() {
+ Runnable runnable = new Runnable() {
+ public void run() {
+ intProp = 3;
+ boolProp = true;
+ if (strProp.equals("foo")) {
+ strProp = "bar";
+ } else {
+ strProp = "foo";
+ }
+ strAProp = new String[]{"foo", "bar", "baz"};
+ intAProp = new int[]{3, 2, 1};
+ }
+ };
+ new Thread(runnable).start();
+
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties p = new Properties();
+ p.put("intProp", new Integer(intProp));
+ p.put("boolProp", new Boolean(boolProp));
+ p.put("strProp", strProp);
+ p.put("strAProp", strAProp);
+ p.put("intAProp", intAProp);
+ return p;
+ }
+
+ public boolean getBoolean() {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ intProp = 3;
+ boolProp = true;
+ if (strProp.equals("foo")) {
+ strProp = "bar";
+ } else {
+ strProp = "foo";
+ }
+ strAProp = new String[]{"foo", "bar", "baz"};
+ intAProp = new int[]{3, 2, 1};
+ }
+ };
+
+ Thread thread = new Thread(runnable);
+ thread.start();
+
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NullCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NullCheckServiceProvider.java
new file mode 100644
index 0000000..f6e85d7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/NullCheckServiceProvider.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class NullCheckServiceProvider implements FooService {
+
+ private String prop1;
+ private String prop2;
+
+ public NullCheckServiceProvider() {
+ if (prop1 == null) {
+ prop2= "0";
+ }
+ }
+
+
+ public boolean foo() {
+ if (prop1 == null && prop2 != null) {
+ prop1 = "0";
+ prop2 = null;
+ return true;
+ }
+ if (prop2 == null && prop1 != null) {
+ prop1 = null;
+ prop2 = "0";
+ return true;
+ }
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleClass.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleClass.java
new file mode 100644
index 0000000..1ea47a1
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/SimpleClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+public class SimpleClass {
+
+ // This class do not implement any interface, it will be exposed as SimpleClass
+
+ public String hello() {
+ return "Hello";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/callbacks/CallbacksCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/callbacks/CallbacksCheckService.java
new file mode 100644
index 0000000..a2189ad
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/callbacks/CallbacksCheckService.java
@@ -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.felix.ipojo.runtime.core.components.callbacks;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+public class CallbacksCheckService implements FooService, CheckService {
+
+ // 4 Counters
+ int registered = 0;
+ int unregistered = 0;
+ int registered2 = 0;
+ int unregistered2 = 0;
+
+ // 4 Methods
+ public void registered(ServiceReference ref) {
+ if (ref == null) {
+ throw new IllegalArgumentException("ref null");
+ }
+ registered++;
+ }
+
+ public void unregistered(ServiceReference ref) {
+ if (ref == null) {
+ throw new IllegalArgumentException("ref null");
+ }
+ unregistered++;
+ }
+
+ public void registered2(ServiceReference ref) {
+ if (ref == null) {
+ throw new IllegalArgumentException("ref null");
+ }
+ registered2++;
+ }
+
+ public void unregistered2(ServiceReference ref) {
+ if (ref == null) {
+ throw new IllegalArgumentException("ref null");
+ }
+ unregistered2++;
+ }
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ Properties props = new Properties();
+ props.put("registered", new Integer(registered));
+ props.put("registered2", new Integer(registered2));
+ props.put("unregistered", new Integer(unregistered));
+ props.put("unregistered2", new Integer(unregistered2));
+ return props;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean check() {
+ return true;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("registered", new Integer(registered));
+ props.put("registered2", new Integer(registered2));
+ props.put("unregistered", new Integer(unregistered));
+ props.put("unregistered2", new Integer(unregistered2));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/ControllerCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/ControllerCheckService.java
new file mode 100644
index 0000000..d35cb7c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/ControllerCheckService.java
@@ -0,0 +1,75 @@
+/*
+ * 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.controller;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class ControllerCheckService implements FooService, CheckService {
+
+
+ private boolean controller;
+
+ public boolean foo() {
+ return controller;
+ }
+
+ public Properties fooProps() {
+ Properties props = new Properties();
+ props.put("controller", new Boolean(controller));
+ return props;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean check() {
+ System.out.println("Before : " + controller);
+ controller = ! controller; // Change
+ System.out.println("After : " + controller);
+ return controller;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("controller", new Boolean(controller));
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/DoubleControllerCheckService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/DoubleControllerCheckService.java
new file mode 100644
index 0000000..6976508
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/controller/DoubleControllerCheckService.java
@@ -0,0 +1,85 @@
+/*
+ * 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.controller;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class DoubleControllerCheckService implements FooService, CheckService {
+
+
+ private boolean controllerFoo;
+ private boolean controllerCS;
+
+ public boolean foo() {
+ controllerFoo = ! controllerFoo;
+ return controllerFoo;
+ }
+
+ public Properties fooProps() {
+ Properties props = new Properties();
+ props.put("controller", new Boolean(controllerFoo));
+
+ controllerCS = true;
+ controllerFoo = true;
+
+ return props;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+ public boolean check() {
+ controllerCS = ! controllerCS;
+ return controllerCS;
+ }
+
+ public Properties getProps() {
+ Properties props = new Properties();
+ props.put("controller", new Boolean(controllerCS));
+
+ // Invert both
+ controllerCS = ! controllerCS;
+ controllerFoo = ! controllerFoo;
+
+ return props;
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/a/IA.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/a/IA.java
new file mode 100644
index 0000000..2cb2285
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/a/IA.java
@@ -0,0 +1,26 @@
+/*
+ * 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.inheritance.a;
+
+public interface IA {
+
+ public String methOne();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/b/IB.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/b/IB.java
new file mode 100644
index 0000000..1b7cee4
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/b/IB.java
@@ -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.felix.ipojo.runtime.core.components.inheritance.b;
+
+import org.apache.felix.ipojo.runtime.core.components.inheritance.a.IA;
+
+public interface IB extends IA {
+
+ public String methTwo();
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/c/C.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/c/C.java
new file mode 100644
index 0000000..d0dbc00
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/c/C.java
@@ -0,0 +1,38 @@
+/*
+ * 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.inheritance.c;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.b.IB;
+
+@Component
+@Provides
+public class C implements IB {
+
+ public String methOne() {
+ return "one";
+ }
+
+ public String methTwo() {
+ return "two";
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/d/D.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/d/D.java
new file mode 100644
index 0000000..0cc06bf
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inheritance/d/D.java
@@ -0,0 +1,59 @@
+/*
+ * 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.inheritance.d;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.Validate;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.a.IA;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.b.IB;
+
+@Component
+public class D {
+ @Requires
+ private IB[] cImpls;
+ private IB cImplDesired;
+
+ // works if I use following instead and cast to C type below
+ // in for loop
+ // but this creates dependency on bundle C instead of just
+ // the interface bundles A & B
+ // @Requires(default-implementation=C)
+ // private iB[] cImpls;
+ // private C cImplDesired;
+
+ @Validate
+ public void start() {
+ for (IB iimpl : cImpls) {
+
+ // works just fine
+ System.out.println("iimpl : " + iimpl);
+ System.out.println(iimpl.methTwo());
+
+ // following produces
+ // invalid D instance with NoMethodFoundError
+ // unless I cast to C instead of iA
+ if (((IA) iimpl).methOne().equals("one")) {
+ cImplDesired = iimpl;
+ System.out.println(iimpl.methOne());
+ }
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation1.java
new file mode 100644
index 0000000..5adbb4f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation1.java
@@ -0,0 +1,45 @@
+/*
+ * 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.inherited;
+
+import org.apache.felix.ipojo.runtime.core.services.ChildInterface;
+
+public class ProcessImplementation1 implements ChildInterface {
+
+ public void processChild() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent1() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParentParent() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent2() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation2.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation2.java
new file mode 100644
index 0000000..22071e5
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation2.java
@@ -0,0 +1,44 @@
+/*
+ * 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.inherited;
+
+
+public class ProcessImplementation2 extends ProcessParentImplementation {
+
+ public void processChild() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent1() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParentParent() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent2() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation3.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation3.java
new file mode 100644
index 0000000..f5f4959
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation3.java
@@ -0,0 +1,82 @@
+/*
+ * 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.inherited;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class ProcessImplementation3 extends ProcessParentImplementation implements FooService {
+
+ public void processChild() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent1() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParentParent() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent2() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean foo() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public Properties fooProps() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean getBoolean() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public double getDouble() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getInt() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public long getLong() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public Boolean getObject() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation4.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation4.java
new file mode 100644
index 0000000..ff183ce
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessImplementation4.java
@@ -0,0 +1,82 @@
+/*
+ * 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.inherited;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class ProcessImplementation4 extends ProcessImplementation2 implements FooService {
+
+ public void processChild() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent1() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParentParent() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent2() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean foo() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public Properties fooProps() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean getBoolean() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public double getDouble() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getInt() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public long getLong() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public Boolean getObject() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessParentImplementation.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessParentImplementation.java
new file mode 100644
index 0000000..c6f278e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/inherited/ProcessParentImplementation.java
@@ -0,0 +1,46 @@
+/*
+ * 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.inherited;
+
+import org.apache.felix.ipojo.runtime.core.services.ChildInterface;
+
+public class ProcessParentImplementation implements ChildInterface {
+
+ public void processChild() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent1() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParentParent() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void processParent2() {
+ // TODO Auto-generated method stub
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/BarConsumer.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/BarConsumer.java
new file mode 100644
index 0000000..b8ca22d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/BarConsumer.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.components.strategies;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+public class BarConsumer implements CheckService {
+
+ private BarService bs;
+
+
+ public boolean check() {
+ return bs.bar();
+ }
+
+ public Properties getProps() {
+ Properties props = bs.getProps();
+ props.put("object", bs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/Consumer.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/Consumer.java
new file mode 100644
index 0000000..e232147
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/Consumer.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.runtime.core.components.strategies;
+
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class Consumer implements CheckService {
+
+ private FooService fs;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = fs.fooProps();
+ props.put("object", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy.java
new file mode 100644
index 0000000..58165d2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy.java
@@ -0,0 +1,191 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.handlers.providedservice.CreationStrategy;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.*;
+
+public class DummyCreationStrategy extends CreationStrategy implements InvocationHandler {
+
+ /**
+ * Map [ComponentInstance->ServiceObject] storing created service objects.
+ */
+ private Map/*<ComponentInstance, ServiceObject>*/ m_instances = new HashMap();
+
+ private InstanceManager m_manager;
+
+ private String[] m_specs;
+
+ /**
+ * A method is invoked on the proxy object.
+ * If the method is the {@link org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)}
+ * method, this method creates a service object if no already created for the asking
+ * component instance.
+ * If the method is {@link org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, Object)}
+ * the service object is unget (i.e. removed from the map and deleted).
+ * In all other cases, a {@link UnsupportedOperationException} is thrown as this policy
+ * requires to use the {@link org.apache.felix.ipojo.IPOJOServiceFactory} interaction pattern.
+ * @param arg0 the proxy object
+ * @param arg1 the called method
+ * @param arg2 the arguments
+ * @return the service object attached to the asking instance for 'get',
+ * <code>null</code> for 'unget',
+ * a {@link UnsupportedOperationException} for all other methods.
+ * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
+ */
+ public Object invoke(Object arg0, Method arg1, Object[] arg2) {
+
+ if ("hashCode".equals(arg1.getName())) {
+ return this.hashCode();
+ }
+
+ if ("equals".equals(arg1.getName()) && arg2.length == 1) {
+ return this.equals(arg2[0]);
+ }
+
+ if (isGetServiceMethod(arg1)) {
+ return getService((ComponentInstance) arg2[0]);
+ }
+
+ if (isUngetServiceMethod(arg1)) {
+ ungetService((ComponentInstance) arg2[0], arg2[1]);
+ return null;
+ }
+
+ throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ + "Before calling the service, call the getService(ComponentInstance) method to get "
+ + "the service object. " + arg1.getName());
+ }
+
+ /**
+ * A service object is required.
+ * This policy returns a service object per asking instance.
+ * @param instance the instance requiring the service object
+ * @return the service object for this instance
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)
+ */
+ public Object getService(ComponentInstance instance) {
+ Object obj = m_instances.get(instance);
+ if (obj == null) {
+ obj = m_manager.createPojoObject();
+ m_instances.put(instance, obj);
+ }
+ return obj;
+ }
+
+ /**
+ * A service object is unget.
+ * The service object is removed from the map and deleted.
+ * @param instance the instance releasing the service
+ * @param svcObject the service object
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, Object)
+ */
+ public void ungetService(ComponentInstance instance, Object svcObject) {
+ Object pojo = m_instances.remove(instance);
+ m_manager.deletePojoObject(pojo);
+ }
+
+ /**
+ * The service is going to be registered.
+ * @param im the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ */
+ public void onPublication(InstanceManager im, String[] interfaces,
+ Properties props) {
+
+ m_manager = im;
+ m_specs = interfaces;
+
+ }
+
+ /**
+ * The service is going to be unregistered.
+ * The instance map is cleared. Created object are disposed.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ Collection col = m_instances.values();
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ m_manager.deletePojoObject(it.next());
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * OSGi Service Factory getService method.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @return a proxy implementing the {@link org.apache.felix.ipojo.IPOJOServiceFactory}
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ Object proxy = Proxy.newProxyInstance(m_manager.getClazz().getClassLoader(),
+ getSpecificationsWithIPOJOServiceFactory(m_specs, m_manager.getContext()), this);
+ return proxy;
+ }
+
+ /**
+ * OSGi Service factory unget method.
+ * Does nothing.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the service object created for this bundle.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) { }
+
+ /**
+ * Utility method returning the class array of provided service
+ * specification and the {@link org.apache.felix.ipojo.IPOJOServiceFactory} interface.
+ * @param specs the published service interface
+ * @param bc the bundle context, used to load classes
+ * @return the class array containing provided service specification and
+ * the {@link org.apache.felix.ipojo.IPOJOServiceFactory} class.
+ */
+ private Class[] getSpecificationsWithIPOJOServiceFactory(String[] specs, BundleContext bc) {
+ Class[] classes = new Class[specs.length + 1];
+ int i = 0;
+ for (i = 0; i < specs.length; i++) {
+ try {
+ classes[i] = bc.getBundle().loadClass(specs[i]);
+ } catch (ClassNotFoundException e) {
+ // Should not happen.
+ }
+ }
+ classes[i] = IPOJOServiceFactory.class;
+ return classes;
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy2.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy2.java
new file mode 100644
index 0000000..1201bd8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyCreationStrategy2.java
@@ -0,0 +1,34 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.handlers.providedservice.strategy.ConfigurableCreationStrategy;
+
+public class DummyCreationStrategy2 extends ConfigurableCreationStrategy {
+
+ protected IPOJOServiceFactory getServiceFactory(InstanceManager manager) {
+ return new DummyServiceFactory(manager);
+ }
+
+
+}
+
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyServiceFactory.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyServiceFactory.java
new file mode 100644
index 0000000..00efbe3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/DummyServiceFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.handlers.providedservice.strategy.ServiceObjectFactory;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class DummyServiceFactory implements ServiceObjectFactory {
+
+ /**
+ * Map [ComponentInstance->ServiceObject] storing created service objects.
+ */
+ private Map/*<ComponentInstance, ServiceObject>*/ m_instances = new HashMap();
+
+ private InstanceManager m_manager;
+
+ public DummyServiceFactory(InstanceManager manager) {
+ m_manager = manager;
+ }
+
+ /**
+ * A service object is required.
+ * This policy returns a service object per asking instance.
+ * @param instance the instance requiring the service object
+ * @return the service object for this instance
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)
+ */
+ public Object getService(ComponentInstance instance) {
+ Object obj = m_instances.get(instance);
+ if (obj == null) {
+ obj = m_manager.createPojoObject();
+ m_instances.put(instance, obj);
+ }
+ return obj;
+ }
+
+ /**
+ * A service object is unget.
+ * The service object is removed from the map and deleted.
+ * @param instance the instance releasing the service
+ * @param svcObject the service object
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, Object)
+ */
+ public void ungetService(ComponentInstance instance, Object svcObject) {
+ Object pojo = m_instances.remove(instance);
+ m_manager.deletePojoObject(pojo);
+ }
+
+ public void close() {
+ Collection col = m_instances.values();
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ m_manager.deletePojoObject(it.next());
+ }
+ m_instances.clear();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooBarProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooBarProviderType1.java
new file mode 100644
index 0000000..19ee35f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooBarProviderType1.java
@@ -0,0 +1,86 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public static long id = 0;
+
+ public static long getNewId() {
+ id++;
+ return id;
+ }
+
+ public static long getReturnedIds() {
+ return id;
+ }
+
+ public static void resetIds() {
+ id = 0;
+ }
+
+ private int m_bar;
+ private String m_foo;
+
+ private long myid = getNewId();
+
+
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ System.out.println(this + " - id : " + myid); //TODO DEBUG
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+
+ p.put("id", new Long(myid));
+ return p;
+ }
+
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ public boolean bar() {
+ return foo();
+ }
+
+ public Properties getProps() {
+ return fooProps();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooProviderType1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooProviderType1.java
new file mode 100755
index 0000000..a8b95ef
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/strategies/FooProviderType1.java
@@ -0,0 +1,86 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+
+import java.util.Properties;
+
+public class FooProviderType1 implements FooService {
+
+ public static long id = 0;
+
+ public static long getNewId() {
+ id++;
+ return id;
+ }
+
+ public static long getReturnedIds() {
+ return id;
+ }
+
+ public static void resetIds() {
+ id = 0;
+ }
+
+ private int m_bar;
+ private String m_foo;
+
+ private long myid = getNewId();
+
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ System.out.println(this + " - id : " + myid); //TODO DEBUG
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if (m_foo != null) {
+ p.put("foo", m_foo);
+ }
+
+ p.put("id", new Long(myid));
+ return p;
+ }
+
+
+ public boolean getBoolean() {
+ return true;
+ }
+
+ public double getDouble() {
+ return 1.0;
+ }
+
+ public int getInt() {
+ return 1;
+ }
+
+ public long getLong() {
+ return 1;
+ }
+
+ public Boolean getObject() {
+ return new Boolean(true);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
new file mode 100644
index 0000000..62eb08d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/BarService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface BarService {
+
+ public boolean bar();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
new file mode 100644
index 0000000..55bf6bb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/CheckService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public static final String foo = "foo";
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ChildInterface.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ChildInterface.java
new file mode 100644
index 0000000..4de4165
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ChildInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services;
+
+public interface ChildInterface extends ParentInterface1, ParentInterface2 {
+
+ public void processChild();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
new file mode 100644
index 0000000..4ce1646
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/FooService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface1.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface1.java
new file mode 100644
index 0000000..5fb00dc
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface1.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services;
+
+public interface ParentInterface1 extends ParentParentInterface {
+
+ public void processParent1();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface2.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface2.java
new file mode 100644
index 0000000..72a8e2a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentInterface2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services;
+
+public interface ParentInterface2 {
+
+ public void processParent2();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentParentInterface.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentParentInterface.java
new file mode 100644
index 0000000..db3a06a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/java/org/apache/felix/ipojo/runtime/core/services/ParentParentInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.services;
+
+public interface ParentParentInterface {
+
+ public void processParentParent();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/basics.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/basics.xml
new file mode 100644
index 0000000..ed7e809
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/basics.xml
@@ -0,0 +1,140 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Simple provider -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="PS-FooProviderType-1" architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="PS-FooProviderType-itf" architecture="true">
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="PS-FooProviderType-3" architecture="true">
+ <provides>
+ <property name="foo" field="m_foo"/>
+ <property name="bar" field="m_bar"/>
+ <property name="baz" type="java.lang.String"/>
+ </provides>
+ <properties propagation="true">
+ <property name="foo" field="m_foo"/>
+ <property name="bar" field="m_bar"/>
+ </properties>
+ </component>
+
+ <!-- Providers providing 2 services -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="PS-FooBarProviderType-1" architecture="true">
+ <provides/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="PS-FooBarProviderType-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService, org.apache.felix.ipojo.runtime.core.services.BarService }"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1"
+ name="PS-FooBarProviderType-3" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.FooService}">
+ <property name="baz" type="java.lang.String" value="foo"/>
+ </provides>
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.BarService}">
+ <property name="baz" type="java.lang.String" value="bar"/>
+ </provides>
+ </component>
+
+
+ <!-- Provider with dynamic property -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn"
+ name="PS-FooProviderType-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2"/>
+ <property name="boolean" field="boolProp" value="false"/>
+ <property name="string" field="strProp" value="foo"/>
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}"/>
+ <property name="intAProp" field="intAProp" value="{1,2,3}"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderType1"
+ name="PS-FooProviderType-2" architecture="true">
+ <provides>
+ <property name="int" type="int" value="2"/>
+ <property name="long" type="long" value="40"/>
+ <property name="string" type="java.lang.String" value="foo"/>
+ <property name="strAProp" type="java.lang.String[]"
+ value="{foo, bar}"/>
+ <property name="intAProp" type="int[]" value="{1,2,3}"/>
+ </provides>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderTypeDyn2"
+ name="PS-FooProviderType-Dyn2" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="4"/>
+ <property name="boolean" field="boolProp"/>
+ <property name="string" field="strProp"/>
+ <property name="strAProp" field="strAProp"/>
+ <property name="intAProp" field="intAProp"
+ value="{1, 2,3 }"/>
+ </provides>
+ </component>
+
+ <!-- Null Check -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.NullCheckServiceProvider" immediate="true"
+ name="PS-Null">
+ <provides>
+ <property field="prop1"/>
+ <property field="prop2"/>
+ </provides>
+ </component>
+
+ <!-- Anonymous classes -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.FooProviderWithAnonymousClass"
+ name="PS-FooProviderTypeAnonymous-Dyn" architecture="true">
+ <provides>
+ <property name="int" field="intProp" value="2"/>
+ <property name="boolean" field="boolProp" value="false"/>
+ <property name="string" field="strProp" value="foo"/>
+ <property name="strAProp" field="strAProp"
+ value="{foo, bar}"/>
+ <property name="intAProp" field="intAProp" value="{1,2,3}"/>
+ </provides>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/callbacks/callbacks.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/callbacks/callbacks.xml
new file mode 100644
index 0000000..91ff1c2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/callbacks/callbacks.xml
@@ -0,0 +1,60 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Registration callbacks -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.callbacks.CallbacksCheckService"
+ name="PS-Callbacks-reg-only">
+ <provides post-registration="registered"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.callbacks.CallbacksCheckService"
+ name="PS-Callbacks-both">
+ <provides post-registration="registered" post-unregistration="unregistered"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.callbacks.CallbacksCheckService"
+ name="PS-Callbacks-unreg-only">
+ <provides post-unregistration="unregistered"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.callbacks.CallbacksCheckService"
+ name="PS-Callbacks-both-2">
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.FooService"
+ post-unregistration="unregistered" post-registration="registered"/>
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.CheckService"
+ post-unregistration="unregistered2" post-registration="registered2"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.callbacks.CallbacksCheckService"
+ name="PS-Callbacks-both-1">
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.FooService"
+ post-unregistration="unregistered" post-registration="registered"/>
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.CheckService"
+ post-unregistration="unregistered" post-registration="registered"/>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/concrete-abstract.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/concrete-abstract.xml
new file mode 100644
index 0000000..7f0b0c0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/concrete-abstract.xml
@@ -0,0 +1,52 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Concrete and abstract class -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation"
+ name="PS-PI4" architecture="true">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation2"
+ name="PS-PI5" architecture="true">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation4"
+ name="PS-PI6" architecture="true">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation"/>
+ </component>
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation3"
+ name="PS-PI7" architecture="true">
+ <provides specifications="[org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation, org.apache.felix.ipojo.runtime.core.services.FooService]"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.SimpleClass">
+ <provides/>
+ </component>
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/controller/service-controller.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/controller/service-controller.xml
new file mode 100644
index 0000000..96a16af
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/controller/service-controller.xml
@@ -0,0 +1,105 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Service Controller -->
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.ControllerCheckService"
+ name="PS-Controller-1-default">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <controller field="controller"/>
+ </provides>
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.CheckService">
+ </provides>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.ControllerCheckService"
+ name="PS-Controller-1-false">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controller" value="false"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.CheckService">
+ </provides>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-truetrue">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="true"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.CheckService">
+ <controller field="controllerCS" value="true"/>
+ </provides>
+ </component>
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-truefalse">
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.FooService">
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="false"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ <provides specifications="org.apache.felix.ipojo.runtime.core.services.CheckService">
+ <controller field="controllerCS" value="true"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-spec1">
+ <provides>
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="false" specification="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ <controller field="controllerCS" value="true" specification="org.apache.felix.ipojo.runtime.core.services.CheckService"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-spec2">
+ <provides>
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="true" specification="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ <controller field="controllerCS" value="true" specification="org.apache.felix.ipojo.runtime.core.services.CheckService"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-spec3">
+ <provides>
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="true" specification="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ <controller field="controllerCS" value="true"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.core.components.controller.DoubleControllerCheckService"
+ name="PS-Controller-2-spec4">
+ <provides>
+ <property name="test2" type="string" value="test2"/>
+ <controller field="controllerFoo" value="false" specification="org.apache.felix.ipojo.runtime.core.services.FooService"/>
+ <controller field="controllerCS" value="true"/>
+ <property name="test" type="string" value="test"/>
+ </provides>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/cons.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/cons.xml
new file mode 100644
index 0000000..832fffa
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/cons.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<instance component="org.apache.felix.ipojo.runtime.core.components.inheritance.d.D" name="d"/>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/inheritance.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/inheritance.xml
new file mode 100644
index 0000000..e5867db
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/inheritance.xml
@@ -0,0 +1,64 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo"
+>
+
+ <!-- Inherited Provides -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation1"
+ name="PS-PI1" architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation1"
+ name="PS-PI1-1" architecture="true">
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.ParentParentInterface"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation1"
+ name="PS-PI1-2" architecture="true">
+ <provides
+ specifications="{org.apache.felix.ipojo.runtime.core.services.ParentParentInterface, org.apache.felix.ipojo.runtime.core.services.ParentInterface2}"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation2"
+ name="PS-PI2" architecture="true">
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation2"
+ name="PS-PI2-1" architecture="true">
+ <provides
+ specifications="org.apache.felix.ipojo.runtime.core.services.ParentParentInterface"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.inherited.ProcessImplementation3"
+ name="PS-PI3" architecture="true">
+ <provides/>
+ </component>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/provider.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/provider.xml
new file mode 100644
index 0000000..e4ed71a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/inheritance/provider.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+<instance component="org.apache.felix.ipojo.runtime.core.components.inheritance.c.C" name="c"/>
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/strategies/metadata-strategies.xml b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/strategies/metadata-strategies.xml
new file mode 100755
index 0000000..fdda126
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/main/resources/strategies/metadata-strategies.xml
@@ -0,0 +1,77 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+>
+ <!-- Simple provider -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1"
+ name="PSS-FooProviderType-Instance" architecture="true">
+ <provides strategy="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.Consumer"
+ name="PSS-Cons" architecture="true">
+ <requires field="fs" proxy="false"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.BarConsumer"
+ name="PSS-ConsBar" architecture="true">
+ <requires field="bs" proxy="false"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1"
+ name="PSS-FooBarProviderType-Instance" architecture="true">
+ <provides strategy="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1"
+ name="PSS-FooProviderType-Custom" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.runtime.core.components.strategies.DummyCreationStrategy"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1"
+ name="PSS-FooBarProviderType-Custom" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.runtime.core.components.strategies.DummyCreationStrategy"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1"
+ name="PSS-FooProviderType-Custom2" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.runtime.core.components.strategies.DummyCreationStrategy2"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1"
+ name="PSS-FooBarProviderType-Custom2" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.runtime.core.components.strategies.DummyCreationStrategy2"/>
+ </component>
+
+
+</ipojo>
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
new file mode 100644
index 0000000..5a779d2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+ @Override
+ public boolean deployConfigAdmin() {
+ return true;
+ }
+
+ @Override
+ protected List<String> getExtraExports() {
+ return Arrays.asList(
+ "org.apache.felix.ipojo.runtime.core.components",
+ "org.apache.felix.ipojo.runtime.core.components.inherited",
+ "org.apache.felix.ipojo.runtime.core.components.strategies",
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.a",
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.b"
+ );
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallbacks.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallbacks.java
new file mode 100644
index 0000000..aef8576
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestCallbacks.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestCallbacks extends Common {
+
+ @Test
+ public void testWithPostRegistrationOnly() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Callbacks-reg-only");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ Integer reg = (Integer) check.getProps().get("registered");
+ Integer unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(0), unreg);
+
+ ci.stop();
+
+ reg = (Integer) check.getProps().get("registered");
+ unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(0), unreg);
+ }
+
+ @Test
+ public void testWithBoth() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Callbacks-both");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ Integer reg = (Integer) check.getProps().get("registered");
+ Integer unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(0), unreg);
+
+ ci.stop();
+
+ reg = (Integer) check.getProps().get("registered");
+ unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(1), unreg);
+ }
+
+ @Test
+ public void testWithPostUnregistrationOnly() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Callbacks-unreg-only");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ Integer reg = (Integer) check.getProps().get("registered");
+ Integer unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(0), reg);
+ assertEquals(new Integer(0), unreg);
+
+ ci.stop();
+
+ reg = (Integer) check.getProps().get("registered");
+ unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(0), reg);
+ assertEquals(new Integer(1), unreg);
+ }
+
+ @Test
+ public void testWithTwoPairsOfCallbacks() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Callbacks-both-2");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ Integer reg = (Integer) check.getProps().get("registered");
+ Integer unreg = (Integer) check.getProps().get("unregistered");
+ Integer reg2 = (Integer) check.getProps().get("registered2");
+ Integer unreg2 = (Integer) check.getProps().get("unregistered2");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertNotNull(reg2);
+ assertNotNull(unreg2);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(0), unreg);
+ assertEquals(new Integer(1), reg2);
+ assertEquals(new Integer(0), unreg2);
+
+ ci.stop();
+
+ reg = (Integer) check.getProps().get("registered");
+ unreg = (Integer) check.getProps().get("unregistered");
+ reg2 = (Integer) check.getProps().get("registered2");
+ unreg2 = (Integer) check.getProps().get("unregistered2");
+ assertNotNull(reg2);
+ assertNotNull(unreg2);
+ assertEquals(new Integer(1), reg);
+ assertEquals(new Integer(1), unreg);
+ assertEquals(new Integer(1), reg2);
+ assertEquals(new Integer(1), unreg2);
+ }
+
+ @Test
+ public void testWithOnePairForTwoService() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Callbacks-both-1");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ Integer reg = (Integer) check.getProps().get("registered");
+ Integer unreg = (Integer) check.getProps().get("unregistered");
+ assertNotNull(reg);
+ assertNotNull(unreg);
+ assertEquals(new Integer(2), reg);
+ assertEquals(new Integer(0), unreg);
+
+ ci.stop();
+
+ reg = (Integer) check.getProps().get("registered");
+ unreg = (Integer) check.getProps().get("unregistered");
+ assertEquals(new Integer(2), reg);
+ assertEquals(new Integer(2), unreg);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestClass.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestClass.java
new file mode 100644
index 0000000..bf59cfb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestClass.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertNotNull;
+
+public class TestClass extends Common {
+
+ private Factory pi4, pi5, pi6, pi7;
+
+ @Before
+ public void setUp() {
+ pi4 = ipojoHelper.getFactory("PS-PI4");
+ pi5 = ipojoHelper.getFactory("PS-PI5");
+ pi6 = ipojoHelper.getFactory("PS-PI6");
+ pi7 = ipojoHelper.getFactory("PS-PI7");
+ }
+
+ @Test
+ public void testIP4() {
+ ipojoHelper.createComponentInstance(pi4.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName("org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation", "ci");
+ assertNotNull("Check itself", ref1);
+
+ ProcessParentImplementation itself = (ProcessParentImplementation) osgiHelper.getRawServiceObject(ref1);
+
+ itself.processChild();
+ }
+
+ @Test
+ public void testIP5() {
+ ipojoHelper.createComponentInstance(pi5.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName("org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation", "ci");
+ assertNotNull("Check parent", ref1);
+
+ ProcessParentImplementation itself = (ProcessParentImplementation) osgiHelper.getRawServiceObject(ref1);
+
+ itself.processChild();
+
+ }
+
+ @Test
+ public void testIP6() {
+ ipojoHelper.createComponentInstance(pi6.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName("org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation", "ci");
+ assertNotNull("Check parent-parent", ref1);
+
+ ProcessParentImplementation itself = (ProcessParentImplementation) osgiHelper.getRawServiceObject(ref1);
+
+ itself.processChild();
+ }
+
+ @Test
+ public void testIP7() {
+ ipojoHelper.createComponentInstance(pi7.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName("org.apache.felix.ipojo.runtime.core.components.inherited.ProcessParentImplementation", "ci");
+ assertNotNull("Check parent-parent", ref1);
+
+ ProcessParentImplementation itself = (ProcessParentImplementation) osgiHelper.getRawServiceObject(ref1);
+
+ itself.processChild();
+
+ ServiceReference ref5 = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "ci");
+ assertNotNull("Check FS", ref5);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicProps.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicProps.java
new file mode 100644
index 0000000..b51d6c9
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicProps.java
@@ -0,0 +1,294 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestDynamicProps extends Common {
+
+ @Before
+ public void setUp() {
+ String type = "PS-FooProviderType-Dyn";
+ ipojoHelper.createComponentInstance(type, "FooProvider-1");
+
+ Properties p2 = new Properties();
+ p2.put("instance.name", "FooProvider-2");
+ p2.put("int", new Integer(4));
+ p2.put("boolean", new Boolean(false));
+ p2.put("string", new String("bar"));
+ p2.put("strAProp", new String[]{"bar", "foo"});
+ p2.put("intAProp", new int[]{1, 2, 3});
+ ipojoHelper.createComponentInstance(type, p2);
+
+ String type2 = "PS-FooProviderType-Dyn2";
+ Properties p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", new Integer(0));
+ p3.put("boolean", new Boolean(true));
+ p3.put("string", new String(""));
+ p3.put("strAProp", new String[0]);
+ p3.put("intAProp", new int[0]);
+ ipojoHelper.createComponentInstance(type2, p3);
+
+ Properties p4 = new Properties();
+ p4.put("instance.name", "FooProvider-4");
+ ipojoHelper.createComponentInstance(type2, p4);
+
+ }
+
+ @Test
+ public void testProperties1() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (1)", intProp, new Integer(2));
+ assertEquals("Check longProp equality (1)", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality (1)", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity (1)", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (1)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (1)");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (2)", intProp, new Integer(3));
+ assertEquals("Check longProp equality (2)", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality (2)", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity (2)", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (2)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity (2)", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (2)");
+ }
+ }
+
+ fs = null;
+ }
+
+ @Test
+ public void testProperties2() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-2");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"bar", "foo"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(3));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ fs = null;
+ }
+
+ @Test
+ public void testProperties3() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String(""));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[0];
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[0];
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hidding (no value)", intAProp);
+
+ fs = null;
+ }
+
+ @Test
+ public void testProperties4() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-4");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Object boolProp = sr.getProperty("boolean");
+ Object strProp = sr.getProperty("string");
+ Object strAProp = sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4)); // Set by the component type.
+ assertEquals("Check boolProp equality", boolProp, null);
+ assertEquals("Check strProp equality", strProp, null);
+ assertNull("Check strAProp nullity", strAProp);
+ assertNotNull("Check intAProp not nullity", intAProp); // Set by the component type.
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < ((String[]) strAProp).length; i++) {
+ if (!((String[]) strAProp)[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hidding (no value)", intAProp);
+
+ fs = null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicPropsReconfiguration.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicPropsReconfiguration.java
new file mode 100644
index 0000000..f37abd8
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestDynamicPropsReconfiguration.java
@@ -0,0 +1,758 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerMethod;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.ow2.chameleon.testing.helpers.TimeUtils;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+@ExamReactorStrategy(PerMethod.class)
+public class TestDynamicPropsReconfiguration extends Common {
+ ComponentInstance fooProvider3, fooProvider4;
+
+
+ @Before
+ public void setUp() {
+ String type2 = "PS-FooProviderType-Dyn2";
+ Properties p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", 0);
+ p3.put("boolean", true);
+ p3.put("string", "");
+ p3.put("strAProp", new String[0]);
+ p3.put("intAProp", new int[0]);
+ fooProvider3 = ipojoHelper.createComponentInstance(type2, p3);
+
+ fooProvider4 = ipojoHelper.createComponentInstance(type2, "FooProvider-4");
+ }
+
+ @Test
+ public void testFactoryReconf() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String(""));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[0];
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[0];
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ServiceReference fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ Factory fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ Properties p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", 1);
+ p3.put("boolean", true);
+ p3.put("string", "foo");
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hidding (no value)", intAProp);
+
+ // Reconfiguration
+ fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", 1);
+ p3.put("boolean", true);
+ p3.put("string", "foo");
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testFactoryReconfString() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[0];
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[0];
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ServiceReference fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ Factory fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ Properties p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", "1");
+ p3.put("boolean", "true");
+ p3.put("string", "foo");
+ p3.put("strAProp", "{foo, bar, baz}");
+ p3.put("intAProp", "{1, 2, 3}");
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hiding (no value)", intAProp);
+
+ // Reconfiguration
+ fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", "1");
+ p3.put("boolean", "true");
+ p3.put("string", "foo");
+ p3.put("strAProp", "{foo, bar, baz}");
+ p3.put("intAProp", "{ 1, 2, 3}");
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testReconfigurationUsingManagedService() throws IOException, InterruptedException {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[0];
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[0];
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ Configuration configuration = admin.getConfiguration("FooProvider-3", "?");
+
+ Dictionary<String, Object> p3 = new Hashtable<String, Object>();
+ p3.put("int", 1);
+ p3.put("boolean", true);
+ p3.put("string", "foo");
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+
+ configuration.update(p3);
+ TimeUtils.grace(200);
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hiding (no value)", intAProp);
+
+ // Reconfiguration
+
+ p3 = new Hashtable<String, Object>();
+ p3.put("int", 1);
+ p3.put("boolean", true);
+ p3.put("string", "foo");
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+
+ configuration.update(p3);
+ TimeUtils.grace(200);
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testReconfiguraitonUsingManagedServiceWithStrings() throws IOException, InterruptedException {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(0));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[0];
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[0];
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ Configuration configuration = admin.getConfiguration("FooProvider-3", "?");
+
+
+ Dictionary<String, Object> p3 = new Hashtable<String, Object>();
+ p3.put("int", "1");
+ p3.put("boolean", "true");
+ p3.put("string", "foo");
+ p3.put("strAProp", "{foo, bar, baz}");
+ p3.put("intAProp", "{ 1, 2, 3}");
+
+ configuration.update(p3);
+ TimeUtils.grace(200);
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hidding (no value)", intAProp);
+
+ // Reconfiguration
+
+ p3 = new Hashtable<String, Object>();
+ p3.put("int", "1");
+ p3.put("boolean", "true");
+ p3.put("string", "foo");
+ p3.put("strAProp", "{foo, bar, baz}");
+ p3.put("intAProp", "{ 1, 2, 3}");
+
+ configuration.update(p3);
+ TimeUtils.grace(200);
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, Boolean.TRUE);
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testFactoryReconfNoValue() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-4");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Object boolProp = sr.getProperty("boolean");
+ Object strProp = sr.getProperty("string");
+ Object strAProp = sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", boolProp, null);
+ assertEquals("Check strProp equality", strProp, null);
+ assertNull("Check strAProp nullity", strAProp);
+
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ServiceReference fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ Factory fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ Properties p3 = new Properties();
+ p3.put("instance.name", "FooProvider-4");
+ p3.put("int", new Integer(1));
+ p3.put("boolean", new Boolean(true));
+ p3.put("string", new String("foo"));
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-4");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < ((String[]) strAProp).length; i++) {
+ if (!((String[]) strAProp)[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar"};
+ for (int i = 0; i < ((String[]) strAProp).length; i++) {
+ if (!((String[]) strAProp)[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNull("Check intAProp hidding (no value)", intAProp);
+
+ // Reconfiguration
+ fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-Dyn2");
+ fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ p3 = new Properties();
+ p3.put("instance.name", "FooProvider-3");
+ p3.put("int", new Integer(1));
+ p3.put("boolean", new Boolean(true));
+ p3.put("string", new String("foo"));
+ p3.put("strAProp", new String[]{"foo", "bar", "baz"});
+ p3.put("intAProp", new int[]{1, 2, 3});
+ try {
+ fact.reconfigure(p3);
+ } catch (Exception e) {
+ fail("Unable to reconfigure the instance with : " + p3);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-3");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(1));
+ assertEquals("Check longProp equality", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < ((String[]) strAProp).length; i++) {
+ if (!((String[]) strAProp)[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ fact = null;
+ fs = null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExposition.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExposition.java
new file mode 100644
index 0000000..27c36ae
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestExposition.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class TestExposition extends Common {
+
+ private ComponentInstance fooProviderSimple;
+ private ComponentInstance fooProviderItf;
+ private ComponentInstance fooBarProvider;
+ private ComponentInstance fooBarProvider2;
+ private ComponentInstance fooBarProvider3;
+
+ @Before
+ public void setUp() {
+ fooProviderSimple = ipojoHelper.createComponentInstance("PS-FooProviderType-1", "fooProviderSimple");
+
+ fooProviderItf = ipojoHelper.createComponentInstance("PS-FooProviderType-itf", "fooProviderItf");
+
+ fooBarProvider = ipojoHelper.createComponentInstance("PS-FooBarProviderType-1", "fooProviderItfs");
+
+ fooBarProvider2 = ipojoHelper.createComponentInstance("PS-FooBarProviderType-2", "fooProviderItfs2");
+
+ fooBarProvider3 = ipojoHelper.createComponentInstance("PS-FooBarProviderType-3", "fooProviderItfs3");
+
+ assertNotNull("Check the instance creation of fooProviderSimple", fooProviderSimple);
+ assertNotNull("Check the instance creation of fooProviderItf", fooProviderItf);
+ assertNotNull("Check the instance creation of fooProviderItfs", fooBarProvider);
+ assertNotNull("Check the instance creation of fooProviderItfs2", fooBarProvider2);
+ assertNotNull("Check the instance creation of fooProviderItfs3", fooBarProvider3);
+
+ }
+
+
+ @Test
+ public void testSimpleExposition() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProviderSimple.getInstanceName());
+ assertNotNull("Check the availability of the FS from " + fooProviderSimple.getInstanceName(), ref);
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check fs invocation", fs.foo());
+ fooProviderSimple.stop();
+ assertFalse("Check the absence of the FS from " + fooProviderSimple.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(FooService.class.getName(), fooProviderSimple.getInstanceName()));
+ }
+
+ @Test
+ public void testItfExposition() {
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooProviderItf.getInstanceName());
+ assertNotNull("Check the availability of the FS from " + fooProviderItf.getInstanceName(), ref);
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("Check fs invocation", fs.foo());
+ fooProviderItf.stop();
+
+ assertFalse("Check the absence of the FS from " + fooProviderSimple.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(FooService.class.getName(), fooProviderItf.getInstanceName()));
+ }
+
+ @Test
+ public void testItfsExposition() {
+ ServiceReference refFoo = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooBarProvider.getInstanceName());
+ assertNotNull("Check the availability of the FS from " + fooBarProvider.getInstanceName(), refFoo);
+ ServiceReference refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), fooBarProvider.getInstanceName());
+ assertNotNull("Check the availability of the BS from " + fooBarProvider.getInstanceName(), refBar);
+
+ assertSame("Check service reference equality", refFoo, refBar);
+
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(refFoo);
+ assertTrue("Check fs invocation", fs.foo());
+
+ BarService bs = (BarService) osgiHelper.getRawServiceObject(refBar);
+ assertTrue("Check bs invocation", bs.bar());
+
+ fooBarProvider.stop();
+
+ assertFalse("Check the absence of the FS from " + fooBarProvider.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(FooService.class.getName(), fooBarProvider.getInstanceName()));
+ assertFalse("Check the absence of the BS from " + fooBarProvider.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(BarService.class.getName(), fooBarProvider.getInstanceName()));
+ }
+
+ @Test
+ public void testItfsExposition2() {
+ ServiceReference refFoo = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooBarProvider2.getInstanceName());
+ assertNotNull("Check the availability of the FS from " + fooBarProvider2.getInstanceName(), refFoo);
+ ServiceReference refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), fooBarProvider2.getInstanceName());
+ assertNotNull("Check the availability of the BS from " + fooBarProvider2.getInstanceName(), refBar);
+
+ assertSame("Check service reference equality", refFoo, refBar);
+
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(refFoo);
+ assertTrue("Check fs invocation", fs.foo());
+
+ BarService bs = (BarService) osgiHelper.getRawServiceObject(refBar);
+ assertTrue("Check bs invocation", bs.bar());
+
+ fooBarProvider2.stop();
+
+ assertFalse("Check the absence of the FS from " + fooBarProvider2.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(FooService.class.getName(), fooBarProvider2.getInstanceName()));
+ assertFalse("Check the absence of the BS from " + fooBarProvider2.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(BarService.class.getName(), fooBarProvider2.getInstanceName()));
+ }
+
+ @Test
+ public void testItfsExposition3() {
+ ServiceReference refFoo = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), fooBarProvider3.getInstanceName());
+ assertNotNull("Check the availability of the FS from " + fooBarProvider3.getInstanceName(), refFoo);
+ ServiceReference refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), fooBarProvider3.getInstanceName());
+ assertNotNull("Check the availability of the BS from " + fooBarProvider3.getInstanceName(), refBar);
+
+ assertNotSame("Check service reference inequality", refFoo, refBar);
+
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(refFoo);
+ assertTrue("Check fs invocation", fs.foo());
+
+ BarService bs = (BarService) osgiHelper.getRawServiceObject(refBar);
+ assertTrue("Check bs invocation", bs.bar());
+
+ // Check properties
+ String baz1 = (String) refFoo.getProperty("baz");
+ String baz2 = (String) refBar.getProperty("baz");
+
+ assertEquals("Check Baz Property 1", baz1, "foo");
+ assertEquals("Check Baz Property 2", baz2, "bar");
+
+ fooBarProvider3.stop();
+
+ assertFalse("Check the absence of the FS from " + fooBarProvider3.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(FooService.class.getName(), fooBarProvider3.getInstanceName()));
+ assertFalse("Check the absence of the BS from " + fooBarProvider3.getInstanceName(),
+ ipojoHelper.isServiceAvailableByName(BarService.class.getName(), fooBarProvider3.getInstanceName()));
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInheritedClasses.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInheritedClasses.java
new file mode 100644
index 0000000..01cae9c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestInheritedClasses.java
@@ -0,0 +1,204 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestInheritedClasses extends Common {
+
+ private Factory pi1, pi11, pi12, pi2, pi21, pi3;
+
+ @Before
+ public void setUp() {
+ pi1 = ipojoHelper.getFactory("PS-PI1");
+ pi11 = ipojoHelper.getFactory("PS-PI1-1");
+ pi12 = ipojoHelper.getFactory("PS-PI1-2");
+
+ pi2 = ipojoHelper.getFactory("PS-PI2");
+ pi21 = ipojoHelper.getFactory("PS-PI2-1");
+
+ pi3 = ipojoHelper.getFactory("PS-PI3");
+ }
+
+ private boolean contains(String[] arr, String txt) {
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].equals(txt)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Test
+ public void testPI1Factory() {
+ String[] specs = pi1.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count", specs.length, 4);
+ assertTrue("Check Child", contains(specs, ChildInterface.class.getName()));
+ assertTrue("Check Parent1", contains(specs, ParentInterface1.class.getName()));
+ assertTrue("Check Parent2", contains(specs, ParentInterface2.class.getName()));
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ }
+
+ @Test
+ public void testPI11Factory() {
+ String[] specs = pi11.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count", specs.length, 1);
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ }
+
+ @Test
+ public void testPI12Factory() {
+ String[] specs = pi12.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count", specs.length, 2);
+ assertTrue("Check Parent2", contains(specs, ParentInterface2.class.getName()));
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ }
+
+ @Test
+ public void testPI2Factory() {
+ String[] specs = pi2.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count (" + specs.length + ")", specs.length, 4);
+ assertTrue("Check Child", contains(specs, ChildInterface.class.getName()));
+ assertTrue("Check Parent1", contains(specs, ParentInterface1.class.getName()));
+ assertTrue("Check Parent2", contains(specs, ParentInterface2.class.getName()));
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ }
+
+ @Test
+ public void testPI21Factory() {
+ String[] specs = pi21.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count", specs.length, 1);
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ }
+
+ @Test
+ public void testPI3Factory() {
+ String[] specs = pi3.getComponentDescription().getprovidedServiceSpecification();
+ assertEquals("Check provides count", specs.length, 5);
+ assertTrue("Check Child", contains(specs, ChildInterface.class.getName()));
+ assertTrue("Check Parent1", contains(specs, ParentInterface1.class.getName()));
+ assertTrue("Check Parent2", contains(specs, ParentInterface2.class.getName()));
+ assertTrue("Check ParentParent", contains(specs, ParentParentInterface.class.getName()));
+ assertTrue("Check FS", contains(specs, FooService.class.getName()));
+ }
+
+ @Test
+ public void testIP1() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi1.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(ChildInterface.class.getName(), "ci");
+ assertNotNull("Check Child", ref1);
+
+ ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(ParentInterface1.class.getName(), "ci");
+ assertNotNull("Check Parent1", ref2);
+
+ ServiceReference ref3 = ipojoHelper.getServiceReferenceByName(ParentInterface2.class.getName(), "ci");
+ assertNotNull("Check Parent2", ref3);
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testIP11() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi11.getName(), "ci");
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testIP12() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi12.getName(), "ci");
+
+ ServiceReference ref3 = ipojoHelper.getServiceReferenceByName(ParentInterface2.class.getName(), "ci");
+ assertNotNull("Check Parent2", ref3);
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testIP2() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi2.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(ChildInterface.class.getName(), "ci");
+ assertNotNull("Check Child", ref1);
+
+ ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(ParentInterface1.class.getName(), "ci");
+ assertNotNull("Check Parent1", ref2);
+
+ ServiceReference ref3 = ipojoHelper.getServiceReferenceByName(ParentInterface2.class.getName(), "ci");
+ assertNotNull("Check Parent2", ref3);
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testIP21() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi21.getName(), "ci");
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testIP3() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance(pi3.getName(), "ci");
+
+ ServiceReference ref1 = ipojoHelper.getServiceReferenceByName(ChildInterface.class.getName(), "ci");
+ assertNotNull("Check Child", ref1);
+
+ ServiceReference ref2 = ipojoHelper.getServiceReferenceByName(ParentInterface1.class.getName(), "ci");
+ assertNotNull("Check Parent1", ref2);
+
+ ServiceReference ref3 = ipojoHelper.getServiceReferenceByName(ParentInterface2.class.getName(), "ci");
+ assertNotNull("Check Parent2", ref3);
+
+ ServiceReference ref4 = ipojoHelper.getServiceReferenceByName(ParentParentInterface.class.getName(), "ci");
+ assertNotNull("Check PP", ref4);
+
+ ServiceReference ref5 = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "ci");
+ assertNotNull("Check FS", ref5);
+
+ ci.dispose();
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java
new file mode 100644
index 0000000..1ba8114
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestListeners.java
@@ -0,0 +1,272 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceListener;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+
+import java.util.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test that the ProvidedServiceHandler calls the ProvidedServiceHandlerListeners when watched provided service changes.
+ */
+public class TestListeners extends Common {
+
+ /**
+ * The number of provided service registrations, incremented by the {@code CountingListener}s.
+ */
+ int registrations = 0;
+
+ /**
+ * The number of provided service unregistrations, incremented by the {@code CountingListener}s.
+ */
+ int unregistrations = 0;
+
+ /**
+ * The number of provided service updates, incremented by the {@code CountingListener}s.
+ */
+ int updates = 0;
+
+ /**
+ * The total number of provided service events, incremented by the {@code TotalCountingListener}s.
+ */
+ int total = 0;
+
+ /**
+ * The {@code instance} arguments received by the {@code AppendingListener}s.
+ */
+ List<ComponentInstance> instances = new ArrayList<ComponentInstance>();
+
+ /**
+ * A ProvidedServiceListener that just count service registrations, updates and unregistrations.
+ */
+ private class CountingListener implements ProvidedServiceListener {
+ public void serviceRegistered(ComponentInstance instance, ProvidedService providedService) {
+ registrations++;
+ }
+ public void serviceModified(ComponentInstance instance, ProvidedService providedService) {
+ updates++;
+ }
+ public void serviceUnregistered(ComponentInstance instance, ProvidedService providedService) {
+ unregistrations++;
+ }
+ }
+
+ /**
+ * A ProvidedServiceListener that just count events.
+ */
+ private class TotalCountingListener implements ProvidedServiceListener {
+ public void serviceRegistered(ComponentInstance instance, ProvidedService providedService) {
+ total++;
+ }
+ public void serviceModified(ComponentInstance instance, ProvidedService providedService) {
+ total++;
+ }
+ public void serviceUnregistered(ComponentInstance instance, ProvidedService providedService) {
+ total++;
+ }
+ }
+
+ /**
+ * A ProvidedServiceListener that just fails.
+ * <p>
+ * Used to ensure that a failing listener does not prevent the following listeners to be called.
+ * </p>
+ */
+ private class ThrowingListener implements ProvidedServiceListener {
+ public void serviceRegistered(ComponentInstance instance, ProvidedService providedService) {
+ throw new RuntimeException("I'm bad");
+ }
+ public void serviceModified(ComponentInstance instance, ProvidedService providedService) {
+ throw new RuntimeException("I'm bad");
+ }
+ public void serviceUnregistered(ComponentInstance instance, ProvidedService providedService) {
+ throw new RuntimeException("I'm bad");
+ }
+ }
+
+ /**
+ * A ProvidedServiceListener that just appends its arguments.
+ */
+ private class AppendingListener implements ProvidedServiceListener {
+ public void serviceRegistered(ComponentInstance instance, ProvidedService providedService) {
+ instances.add(instance);
+ }
+ public void serviceModified(ComponentInstance instance, ProvidedService providedService) {
+ instances.add(instance);
+ }
+ public void serviceUnregistered(ComponentInstance instance, ProvidedService providedService) {
+ instances.add(instance);
+ }
+ }
+
+ /**
+ * Test that the listeners registered on the tested instance are called when the instance provided service is
+ * registered, updated or unregistered.
+ */
+ @Test
+ public void testProvidedServiceListener() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-default");
+ ProvidedServiceHandlerDescription pshd = (ProvidedServiceHandlerDescription) ci.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:provides");
+ ProvidedServiceDescription ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ // Register listeners :
+ // 1- CountingListener l1
+ // 2- ThrowingListener bad
+ // 3- TotalCountingListener l2
+ // 4- AppendingListener l3
+ ProvidedServiceListener l1 = new CountingListener();
+ ps.addListener(l1);
+ ProvidedServiceListener bad = new ThrowingListener();
+ ps.addListener(bad);
+ ProvidedServiceListener l2 = new TotalCountingListener();
+ ps.addListener(l2);
+ ProvidedServiceListener l3 = new AppendingListener();
+ ps.addListener(l3);
+
+ // Check initial valued are untouched
+ assertEquals(0, registrations);
+ assertEquals(0, unregistrations);
+ assertEquals(0, updates);
+ assertEquals(0, total);
+
+ // Unregister the service and check.
+ assertFalse(check.check());
+ assertEquals(0, registrations);
+ assertEquals(1, unregistrations);
+ assertEquals(0, updates);
+ assertEquals(1, total);
+
+ // Modify the service while it is unregistered. Nothing should move.
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put("change1", "1");
+ ps.addProperties(props);
+ assertEquals(0, registrations);
+ assertEquals(1, unregistrations);
+ assertEquals(0, updates);
+ assertEquals(1, total);
+
+ // Register the service and check.
+ assertTrue(check.check());
+ assertEquals(1, registrations);
+ assertEquals(1, unregistrations);
+ assertEquals(0, updates);
+ assertEquals(2, total);
+
+ // Modify the service while it is REGISTERED
+ props.clear();
+ props.put("change2", "2");
+ ps.addProperties(props);
+ assertEquals(1, registrations);
+ assertEquals(1, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(3, total);
+
+ // One more time, just to be sure...
+ assertFalse(check.check()); // Unregister
+ assertEquals(1, registrations);
+ assertEquals(2, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(4, total);
+ assertTrue(check.check()); // Register
+ assertEquals(2, registrations);
+ assertEquals(2, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(5, total);
+
+ // Unregister the listener
+ ps.removeListener(l1);
+ ps.removeListener(bad);
+ ps.removeListener(l2);
+ ps.removeListener(l3);
+
+ // Play with the controller and check that nothing moves
+ assertFalse(check.check()); // Unregister
+ assertEquals(2, registrations);
+ assertEquals(2, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(5, total);
+ assertTrue(check.check()); // Register
+ assertEquals(2, registrations);
+ assertEquals(2, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(5, total);
+ props.clear(); props.put("change3", "3"); ps.addProperties(props); // Modify
+ assertEquals(2, registrations);
+ assertEquals(2, unregistrations);
+ assertEquals(1, updates);
+ assertEquals(5, total);
+
+ // Check that instances contains $total times the ci component instance, and nothing else.
+ assertEquals(5, instances.size());
+ instances.removeAll(Collections.singleton(ci));
+ assertEquals(0, instances.size());
+
+ ci.dispose();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNullProvidedServiceListener() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-default");
+ ProvidedServiceHandlerDescription pshd = (ProvidedServiceHandlerDescription) ci.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:provides");
+ ProvidedServiceDescription ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+
+ // Should fail!
+ ps.addListener(null);
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testRemoveNonexistentProvidedServiceListener() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-default");
+ ProvidedServiceHandlerDescription pshd = (ProvidedServiceHandlerDescription) ci.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:provides");
+ ProvidedServiceDescription ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+
+ // Should fail!
+ ps.removeListener(new ThrowingListener());
+ }
+
+ private ProvidedServiceDescription getPS(String itf, ProvidedServiceDescription[] svc) {
+ for (int i = 0; i < svc.length; i++) {
+ if (svc[i].getServiceSpecifications()[0].equals(itf)) {
+ return svc[i];
+ }
+ }
+
+ fail("Service : " + itf + " not found");
+ return null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNullCheck.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNullCheck.java
new file mode 100644
index 0000000..ac6c2d3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestNullCheck.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestNullCheck extends Common {
+
+ @Test
+ public void testNull() {
+
+ String factName = "PS-Null";
+ String compName = "NullCheck";
+ ServiceReference ref = null;
+
+ // Check that no Foo Service are available
+ ref = osgiHelper.getServiceReference(FooService.class.getName());
+ assertNull("FS already available", ref);
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider-1", fact);
+
+ // Don't give any configuration so, properties are null.
+ ipojoHelper.createComponentInstance(factName, compName);
+
+ // Get a FooService provider
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), "(" + "instance.name" + "=" + compName + ")");
+
+ assertNotNull("FS not available", ref);
+
+ // Check service properties
+ assertNull(ref.getProperty("prop1"));
+ assertNotNull(ref.getProperty("prop2"));
+
+ // Test foo invocation
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("FooService invocation failed", fs.foo());
+
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), "(" + "instance.name" + "=" + compName + ")");
+ // Check service properties
+ assertNotNull(ref.getProperty("prop1"));
+ assertNull(ref.getProperty("prop2"));
+
+ ipojoHelper.dispose();
+
+ // Check that there is no more FooService
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), null);
+
+ assertNull("FS available, but component instance stopped", ref);
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestOSGiProperties.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestOSGiProperties.java
new file mode 100644
index 0000000..17e819f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestOSGiProperties.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestOSGiProperties extends Common {
+
+ @Test
+ public void testOSGiProperties() {
+ String factName = "PS-FooProviderType-1";
+ String compName = "FooProvider-1";
+ ServiceReference ref = null;
+
+ // Check that no Foo Service are available
+ ref = osgiHelper.getServiceReference(FooService.class.getName());
+
+ assertNull("FS already available", ref);
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider-1", fact);
+
+ Dictionary conf = new Properties();
+ conf.put(Constants.SERVICE_DESCRIPTION, "description");
+ conf.put(Constants.SERVICE_RANKING, "10");
+ conf.put(Constants.SERVICE_VENDOR, "ASF");
+ conf.put(Constants.SERVICE_PID, "my.pid");
+
+ ipojoHelper.createComponentInstance(factName, compName, conf);
+
+ // Get a FooService provider
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), "(" + "instance.name" + "=" + compName + ")");
+
+ assertNotNull("FS not available", ref);
+
+ // Check properties
+ assertEquals("description", ref.getProperty(Constants.SERVICE_DESCRIPTION));
+ assertEquals(new Integer(10), ref.getProperty(Constants.SERVICE_RANKING));
+ assertEquals("ASF", ref.getProperty(Constants.SERVICE_VENDOR));
+ assertEquals("my.pid", ref.getProperty(Constants.SERVICE_PID));
+
+
+ // Test foo invocation
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("FooService invocation failed", fs.foo());
+
+ ipojoHelper.dispose();
+
+
+ // Check that there is no more FooService
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), null);
+
+
+ assertNull("FS available, but component instance stopped", ref);
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertiesInAnonymousClass.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertiesInAnonymousClass.java
new file mode 100644
index 0000000..98f9a64
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestPropertiesInAnonymousClass.java
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestPropertiesInAnonymousClass extends Common {
+
+ @Before
+ public void setUp() {
+ String type = "PS-FooProviderTypeAnonymous-Dyn";
+ ipojoHelper.createComponentInstance(type, "FooProviderAno-1");
+
+ }
+
+
+ @Test
+ public void testRunnable() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProviderAno-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (1)", intProp, new Integer(2));
+ assertEquals("Check longProp equality (1)", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality (1)", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity (1)", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (1)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (1)");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.foo());
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProviderAno-1");
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (2)", intProp, new Integer(3));
+ assertEquals("Check longProp equality (2)", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality (2)", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity (2)", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (2)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity (2)", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (2)");
+ }
+ }
+
+ fs = null;
+ }
+
+ @Test
+ public void testWorkerThread() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProviderAno-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Boolean boolProp = (Boolean) sr.getProperty("boolean");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (1)", intProp, new Integer(2));
+ assertEquals("Check longProp equality (1)", boolProp, new Boolean(false));
+ assertEquals("Check strProp equality (1)", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity (1)", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (1)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (1)");
+ }
+ }
+
+ // Invoke
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(sr);
+ assertTrue("invoke fs", fs.getBoolean());
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProviderAno-1");
+ // Re-check the property (change)
+ intProp = (Integer) sr.getProperty("int");
+ boolProp = (Boolean) sr.getProperty("boolean");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality (2)", intProp, new Integer(3));
+ assertEquals("Check longProp equality (2)", boolProp, new Boolean(true));
+ assertEquals("Check strProp equality (2)", strProp, new String("bar"));
+ assertNotNull("Check strAProp not nullity (2)", strAProp);
+ v = new String[]{"foo", "bar", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality (2)");
+ }
+ }
+ assertNotNull("Check intAProp not nullity (2)", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality (2)");
+ }
+ }
+
+ fs = null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestProvidedServiceArchitecture.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestProvidedServiceArchitecture.java
new file mode 100644
index 0000000..34ee6ae
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestProvidedServiceArchitecture.java
@@ -0,0 +1,231 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class TestProvidedServiceArchitecture extends Common {
+
+ @Test
+ public void testExposition() {
+ String factName = "PS-FooProviderType-1";
+ String compName = "FooProvider-1";
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider-1", fact);
+
+ ipojoHelper.createComponentInstance(factName, compName);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), compName);
+ assertNotNull("Architecture not available", arch_ref);
+
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(arch_ref);
+ InstanceDescription id = arch.getInstanceDescription();
+
+ assertEquals("Check component instance name (" + id.getName() + ")", id.getName(), compName);
+ assertEquals("Check component type implementation class", id.getComponentDescription().getClassName(), "org.apache.felix.ipojo.runtime.core.components.FooProviderType1");
+
+ HandlerDescription[] handlers = id.getHandlers();
+ assertEquals("Number of handlers", handlers.length, 2);
+
+ //Look for the ProvidedService Handler
+ ProvidedServiceHandlerDescription pshd = null;
+ pshd = (ProvidedServiceHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:provides");
+
+// for(int i = 0; i < handlers.length; i++) {
+// if(handlers[i].getHandlerName().equals("org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler")) {
+// pshd = (ProvidedServiceHandlerDescription) handlers[i];
+// }
+// }
+//
+ assertNotNull("Check ProvidedServiceHandlerDescription", pshd);
+ ProvidedServiceDescription[] ps = pshd.getProvidedServices();
+
+ assertEquals("Check ProvidedService number", ps.length, 1);
+ assertEquals("Check Provided Service Specs - 1", ps[0].getServiceSpecifications().length, 1);
+ assertEquals("Check Provided Service Specs - 2", ps[0].getServiceSpecifications()[0], FooService.class.getName());
+ assertEquals("Check Provided Service availability", ps[0].getState(), ProvidedServiceDescription.REGISTERED);
+ Properties prop = ps[0].getProperties();
+ assertNotNull("Check Props", prop);
+ assertEquals("Check service properties number", prop.size(), 2);
+ assertEquals("Check instance.name property", prop.getProperty("instance.name"), compName);
+ assertEquals("Check factory.name property", prop.getProperty("factory.name"), factName);
+ }
+
+ @Test
+ public void testProps() {
+ String factName = "PS-FooProviderType-3";
+ String compName = "FooProvider";
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider", fact);
+
+ Properties props = new Properties();
+ props.put("instance.name", compName);
+ props.put("foo", "foo");
+ props.put("bar", "2");
+ props.put("baz", "baz");
+ ipojoHelper.createComponentInstance(factName, props);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), compName);
+ assertNotNull("Architecture not available", arch_ref);
+
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(arch_ref);
+ InstanceDescription id = arch.getInstanceDescription();
+
+ assertEquals("Check component instance name (" + id.getName() + ")", id.getName(), compName);
+ assertEquals("Check component type implementation class", id.getComponentDescription().getClassName(), "org.apache.felix.ipojo.runtime.core.components.FooProviderType1");
+
+ HandlerDescription[] handlers = id.getHandlers();
+ assertEquals("Number of handlers", handlers.length, 3);
+
+ //Look for the ProvidedService Handler
+ ProvidedServiceHandlerDescription pshd = null;
+ pshd = (ProvidedServiceHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:provides");
+
+
+ assertNotNull("Check ProvidedServiceHandlerDescription", pshd);
+ ProvidedServiceDescription[] ps = pshd.getProvidedServices();
+
+ assertEquals("Check ProvidedService number", ps.length, 1);
+ assertEquals("Check Provided Service Specs - 1", ps[0].getServiceSpecifications().length, 1);
+ assertEquals("Check Provided Service Specs - 2", ps[0].getServiceSpecifications()[0], FooService.class.getName());
+ assertEquals("Check Provided Service availability", ps[0].getState(), ProvidedServiceDescription.REGISTERED);
+
+ Properties prop = ps[0].getProperties();
+ assertNotNull("Check Props", prop);
+ assertEquals("Check service properties number (#" + prop + "?=5)", prop.size(), 5);
+ assertEquals("Check instance.name property", prop.getProperty("instance.name"), compName);
+ assertEquals("Check factory.name property", prop.getProperty("factory.name"), factName);
+ assertEquals("Check foo property", prop.get("foo"), "foo");
+ assertEquals("Check bar property", prop.get("bar"), new Integer(2));
+ assertEquals("Check baz property", prop.get("baz"), "baz");
+
+ }
+
+ @Test
+ public void testDoubleProviding() {
+ String factName = "PS-FooBarProviderType-1";
+ String compName = "FooProvider";
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider", fact);
+
+ ipojoHelper.createComponentInstance(factName, compName);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), compName);
+ assertNotNull("Architecture not available", arch_ref);
+
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(arch_ref);
+ InstanceDescription id = arch.getInstanceDescription();
+
+ assertEquals("Check component instance name (" + id.getName() + ")", id.getName(), compName);
+ assertEquals("Check component type implementation class", id.getComponentDescription().getClassName(), "org.apache.felix.ipojo.runtime.core.components.FooBarProviderType1");
+
+ HandlerDescription[] handlers = id.getHandlers();
+ assertEquals("Number of handlers", handlers.length, 2);
+
+ //Look for the ProvidedService Handler
+ ProvidedServiceHandlerDescription pshd = null;
+ pshd = (ProvidedServiceHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:provides");
+
+// for(int i = 0; i < handlers.length; i++) {
+// if(handlers[i].getHandlerName().equals("org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler")) {
+// pshd = (ProvidedServiceHandlerDescription) handlers[i];
+// }
+// }
+
+ assertNotNull("Check ProvidedServiceHandlerDescription", pshd);
+ ProvidedServiceDescription[] ps = pshd.getProvidedServices();
+
+ assertEquals("Check ProvidedService number", ps.length, 1);
+ assertEquals("Check Provided Service Specs - 1", ps[0].getServiceSpecifications().length, 2);
+ assertContains("Check provided service specs - 2", ps[0].getServiceSpecifications(), FooService.class.getName());
+ assertContains("Check provided service specs - 2", ps[0].getServiceSpecifications(), BarService.class.getName());
+ assertEquals("Check Provided Service availability", ps[0].getState(), ProvidedServiceDescription.REGISTERED);
+
+ }
+
+ @Test
+ public void testPropsNoValue() {
+ String factName = "PS-FooProviderType-3";
+ String compName = "FooProvider";
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider", fact);
+
+ ipojoHelper.createComponentInstance(factName, compName);
+
+ ServiceReference arch_ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), compName);
+ assertNotNull("Architecture not available", arch_ref);
+
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(arch_ref);
+ InstanceDescription id = arch.getInstanceDescription();
+
+ assertEquals("Check component instance name (" + id.getName() + ")", id.getName(), compName);
+ assertEquals("Check component type implementation class", id.getComponentDescription().getClassName(), "org.apache.felix.ipojo.runtime.core.components.FooProviderType1");
+
+ HandlerDescription[] handlers = id.getHandlers();
+ assertEquals("Number of handlers", handlers.length, 3);
+
+ //Look for the ProvidedService Handler
+ ProvidedServiceHandlerDescription pshd = null;
+ pshd = (ProvidedServiceHandlerDescription) id.getHandlerDescription("org.apache.felix.ipojo:provides");
+
+// for(int i = 0; i < handlers.length; i++) {
+// if(handlers[i].getHandlerName().equals("org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler")) {
+// pshd = (ProvidedServiceHandlerDescription) handlers[i];
+// }
+// }
+
+ assertNotNull("Check ProvidedServiceHandlerDescription", pshd);
+ ProvidedServiceDescription[] ps = pshd.getProvidedServices();
+
+ assertEquals("Check ProvidedService number", ps.length, 1);
+ assertEquals("Check Provided Service Specs - 1", ps[0].getServiceSpecifications().length, 1);
+ assertEquals("Check Provided Service Specs - 2", ps[0].getServiceSpecifications()[0], FooService.class.getName());
+ assertEquals("Check Provided Service availability", ps[0].getState(), ProvidedServiceDescription.REGISTERED);
+
+ Properties prop = ps[0].getProperties();
+ assertNotNull("Check Props", prop);
+ assertEquals("Check service properties number (#" + prop + "?=5)", prop.size(), 2);
+ assertEquals("Check instance.name property", prop.getProperty("instance.name"), compName);
+ assertEquals("Check factory.name property", prop.getProperty("factory.name"), factName);
+
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestServiceController.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestServiceController.java
new file mode 100644
index 0000000..4559512
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestServiceController.java
@@ -0,0 +1,260 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TestServiceController extends Common {
+
+ @Test
+ public void testComponentWithAController() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-default");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ assertFalse(check.check());
+
+ // FooService should not be there anymore
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ assertTrue(check.check());
+
+ assertNotNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithAControllerSetToFalse() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-false");
+ // Controller set to false.
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ assertTrue(check.check());
+ assertNotNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ assertFalse(check.check());
+ // FooService should not be there anymore
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersSetToTrue() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-truetrue");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.check();
+
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNotNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.foo();
+
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersSetToTrueAndFalse() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-truefalse");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ assertFalse(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.getProps();
+
+ assertFalse(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.fooProps();
+
+ assertTrue(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersUsingBothSpecificationsTrueFalse() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-spec1");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ assertFalse(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.getProps();
+
+ assertFalse(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.fooProps();
+
+ assertTrue(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersUsingBothSpecificationsTrueTrue() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-spec2");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.check();
+ // CheckService not available
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNotNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.foo();
+
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersUsingSpecificationAndAllTrueTrue() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-spec3");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.check();
+ // CheckService not available
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNotNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.foo();
+
+ assertNull(osgiHelper.getServiceReference(CheckService.class.getName()));
+ assertNull(osgiHelper.getServiceReference(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testComponentWithTwoControllersUsingSpecificationAndAllTrueFalse() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-2-spec4");
+
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ assertFalse(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ check.getProps();
+
+ assertFalse(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ FooService fs = (FooService) osgiHelper.getServiceObject(FooService.class.getName(), null);
+ fs.fooProps();
+
+ assertTrue(osgiHelper.isServiceAvailable(CheckService.class.getName()));
+ assertTrue(osgiHelper.isServiceAvailable(FooService.class.getName()));
+
+ ci.dispose();
+ }
+
+ @Test
+ public void testArchitecture() {
+ ComponentInstance ci = ipojoHelper.createComponentInstance("PS-Controller-1-default");
+ // Controller set to true.
+ osgiHelper.waitForService(FooService.class.getName(), null, 5000);
+ osgiHelper.waitForService(CheckService.class.getName(), null, 5000);
+
+ ProvidedServiceHandlerDescription pshd = null;
+ pshd = (ProvidedServiceHandlerDescription) ci.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:provides");
+
+ ProvidedServiceDescription ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+ assertEquals("true", ps.getController());
+
+ CheckService check = (CheckService) osgiHelper.getServiceObject(CheckService.class.getName(), null);
+ assertNotNull(check);
+
+ assertFalse(check.check());
+
+ ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+ assertEquals("false", ps.getController());
+
+ assertTrue(check.check());
+
+ ps = getPS(FooService.class.getName(), pshd.getProvidedServices());
+ assertEquals("true", ps.getController());
+
+ }
+
+ private ProvidedServiceDescription getPS(String itf, ProvidedServiceDescription[] svc) {
+ for (int i = 0; i < svc.length; i++) {
+ if (svc[i].getServiceSpecifications()[0].equals(itf)) {
+ return svc[i];
+ }
+ }
+
+ fail("Service : " + itf + " not found");
+ return null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimplePS.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimplePS.java
new file mode 100644
index 0000000..485bacb
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestSimplePS.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.components.SimpleClass;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+public class TestSimplePS extends Common {
+
+ @Test
+ public void testPS() {
+ String factName = "PS-FooProviderType-1";
+ String compName = "FooProvider-1";
+ ServiceReference ref;
+
+ // Check that no Foo Service are available
+ ref = osgiHelper.getServiceReference(FooService.class.getName());
+
+ assertNull("FS already available", ref);
+
+ // Get the factory to create a component instance
+ Factory fact = ipojoHelper.getFactory(factName);
+ assertNotNull("Cannot find the factory FooProvider-1", fact);
+
+ ipojoHelper.createComponentInstance(factName, compName);
+
+ // Get a FooService provider
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), "(" + "instance.name" + "=" + compName + ")");
+
+ assertNotNull("FS not available", ref);
+
+ // Test foo invocation
+ FooService fs = (FooService) osgiHelper.getRawServiceObject(ref);
+ assertTrue("FooService invocation failed", fs.foo());
+
+ ipojoHelper.dispose();
+
+
+ // Check that there is no more FooService
+ ref = osgiHelper.getServiceReference(FooService.class.getName(), null);
+
+
+ assertNull("FS available, but component instance stopped", ref);
+
+ }
+
+ @Test
+ public void testWhenNoInterface() {
+ String factoryName = "org.apache.felix.ipojo.runtime.core.components.SimpleClass";
+ ComponentInstance ci = ipojoHelper.createComponentInstance(factoryName);
+ osgiHelper.waitForService(SimpleClass.class.getName(), null, 5000);
+ SimpleClass simple = (SimpleClass) osgiHelper.getServiceObject(SimpleClass.class.getName(), null);
+ assertEquals("Hello", simple.hello());
+ ci.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticProps.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticProps.java
new file mode 100644
index 0000000..344317b
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticProps.java
@@ -0,0 +1,115 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestStaticProps extends Common {
+
+ @Before
+ public void setUp() {
+ String type = "PS-FooProviderType-2";
+
+ ipojoHelper.createComponentInstance(type, "FooProvider-1");
+
+ Properties p2 = new Properties();
+ p2.put("instance.name", "FooProvider-2");
+ p2.put("int", new Integer(4));
+ p2.put("long", new Long(42));
+ p2.put("string", new String("bar"));
+ p2.put("strAProp", new String[]{"bar", "foo"});
+ p2.put("intAProp", new int[]{1, 2, 3});
+ ipojoHelper.createComponentInstance(type, p2);
+
+ }
+
+
+ @Test
+ public void testProperties1() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", longProp, new Long(40));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ }
+
+ @Test
+ public void testProperties2() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-2");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", longProp, new Long(42));
+ assertEquals("Check strProp equality", strProp, new String("bar"));
+
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"bar", "foo"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticPropsReconfiguration.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticPropsReconfiguration.java
new file mode 100644
index 0000000..bfe2f37
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestStaticPropsReconfiguration.java
@@ -0,0 +1,349 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TestStaticPropsReconfiguration extends Common {
+
+ @Before
+ public void setUp() {
+ String type = "PS-FooProviderType-2";
+ ipojoHelper.createComponentInstance(type, "FooProvider-1");
+
+ Properties p2 = new Properties();
+ p2.put("instance.name", "FooProvider-2");
+ p2.put("int", 4);
+ p2.put("long", (long) 42);
+ p2.put("string", "bar");
+ p2.put("strAProp", new String[]{"bar", "foo"});
+ p2.put("intAProp", new int[]{1, 2, 3});
+ ipojoHelper.createComponentInstance(type, p2);
+ }
+
+ @Test
+ public void testReconfFactory1() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", longProp, new Long(40));
+ assertEquals("Check strProp equality", strProp, new String("foo"));
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ServiceReference fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-2");
+ Dictionary reconf = new Properties();
+ reconf.put("instance.name", "FooProvider-1");
+ reconf.put("int", new Integer(5));
+ reconf.put("long", new Long(43));
+ reconf.put("string", new String("toto"));
+ reconf.put("strAProp", new String[]{"foo", "baz"});
+ reconf.put("intAProp", new int[]{3, 2, 1});
+ Factory fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ try {
+ fact.reconfigure(reconf);
+ } catch (Exception e) {
+ fail("Configuration non acceptable : " + reconf);
+ }
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties after the reconfiguration
+ intProp = (Integer) sr.getProperty("int");
+ longProp = (Long) sr.getProperty("long");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality after reconfiguration", intProp, new Integer(5));
+ assertEquals("Check longProp equality after reconfiguration", longProp, new Long(43));
+ assertEquals("Check strProp equality after reconfiguration", strProp, new String("toto"));
+ assertNotNull("Check strAProp not nullity after reconfiguration", strAProp);
+ v = new String[]{"foo", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ }
+
+ @Test
+ public void testReconfFactory2() {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-2");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", longProp, new Long(42));
+ assertEquals("Check strProp equality", strProp, "bar");
+
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"bar", "foo"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ServiceReference fact_ref = ipojoHelper.getServiceReferenceByName(Factory.class.getName(), "PS-FooProviderType-2");
+ Properties reconf = new Properties();
+ reconf.put("instance.name", "FooProvider-2");
+ reconf.put("int", 5);
+ reconf.put("long", (long) 43);
+ reconf.put("string", "toto");
+ reconf.put("strAProp", new String[]{"foo", "baz"});
+ reconf.put("intAProp", new int[]{3, 2, 1});
+ Factory fact = (Factory) osgiHelper.getRawServiceObject(fact_ref);
+ try {
+ fact.reconfigure(reconf);
+ } catch (Exception e) {
+ fail("Configuration non acceptable : " + reconf);
+ }
+
+ // Check service properties after the reconfiguration
+ intProp = (Integer) sr.getProperty("int");
+ longProp = (Long) sr.getProperty("long");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality after reconfiguration", intProp, new Integer(5));
+ assertEquals("Check longProp equality after reconfiguration", longProp, new Long(43));
+ assertEquals("Check strProp equality after reconfiguration", strProp, "toto");
+ assertNotNull("Check strAProp not nullity after reconfiguration", strAProp);
+ v = new String[]{"foo", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testMSFFactory1() throws IOException, InterruptedException {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(2));
+ assertEquals("Check longProp equality", longProp, new Long(40));
+ assertEquals("Check strProp equality", strProp, "foo");
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"foo", "bar"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ // Reconfiguration
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ Configuration configuration = admin.getConfiguration("FooProvider-1", "?");
+
+ Dictionary<String, Object> reconf = new Hashtable<String, Object>();
+ reconf.put("int", 5);
+ reconf.put("long", (long) 43);
+ reconf.put("string", "toto");
+ reconf.put("strAProp", new String[]{"foo", "baz"});
+ reconf.put("intAProp", new int[]{3, 2, 1});
+
+ configuration.update(reconf);
+ Thread.sleep(200);
+
+ sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-1");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties after the reconfiguration
+ intProp = (Integer) sr.getProperty("int");
+ longProp = (Long) sr.getProperty("long");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality after reconfiguration", intProp, new Integer(5));
+ assertEquals("Check longProp equality after reconfiguration", longProp, new Long(43));
+ assertEquals("Check strProp equality after reconfiguration", strProp, "toto");
+ assertNotNull("Check strAProp not nullity after reconfiguration", strAProp);
+ v = new String[]{"foo", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+ @Test
+ public void testReconfMSF2() throws IOException, InterruptedException {
+ ServiceReference sr = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), "FooProvider-2");
+ assertNotNull("Check the availability of the FS service", sr);
+
+ // Check service properties
+ Integer intProp = (Integer) sr.getProperty("int");
+ Long longProp = (Long) sr.getProperty("long");
+ String strProp = (String) sr.getProperty("string");
+ String[] strAProp = (String[]) sr.getProperty("strAProp");
+ int[] intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality", intProp, new Integer(4));
+ assertEquals("Check longProp equality", longProp, new Long(42));
+ assertEquals("Check strProp equality", strProp, "bar");
+
+ assertNotNull("Check strAProp not nullity", strAProp);
+ String[] v = new String[]{"bar", "foo"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ int[] v2 = new int[]{1, 2, 3};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+
+ ConfigurationAdmin admin = osgiHelper.getServiceObject(ConfigurationAdmin.class);
+ Configuration configuration = admin.getConfiguration("FooProvider-2", "?");
+
+ // Reconfiguration
+ Dictionary<String, Object> reconf = new Hashtable<String, Object>();
+ reconf.put("int", 5);
+ reconf.put("long", (long) 43);
+ reconf.put("string", "toto");
+ reconf.put("strAProp", new String[]{"foo", "baz"});
+ reconf.put("intAProp", new int[]{3, 2, 1});
+
+ configuration.update(reconf);
+ Thread.sleep(200);
+
+ // Check service properties after the reconfiguration
+ intProp = (Integer) sr.getProperty("int");
+ longProp = (Long) sr.getProperty("long");
+ strProp = (String) sr.getProperty("string");
+ strAProp = (String[]) sr.getProperty("strAProp");
+ intAProp = (int[]) sr.getProperty("intAProp");
+
+ assertEquals("Check intProp equality after reconfiguration", intProp, new Integer(5));
+ assertEquals("Check longProp equality after reconfiguration", longProp, new Long(43));
+ assertEquals("Check strProp equality after reconfiguration", strProp, "toto");
+ assertNotNull("Check strAProp not nullity after reconfiguration", strAProp);
+ v = new String[]{"foo", "baz"};
+ for (int i = 0; i < strAProp.length; i++) {
+ if (!strAProp[i].equals(v[i])) {
+ fail("Check the strAProp Equality");
+ }
+ }
+ assertNotNull("Check intAProp not nullity", intAProp);
+ v2 = new int[]{3, 2, 1};
+ for (int i = 0; i < intAProp.length; i++) {
+ if (intAProp[i] != v2[i]) {
+ fail("Check the intAProp Equality");
+ }
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/inheritence/InheritanceTest.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/inheritence/InheritanceTest.java
new file mode 100644
index 0000000..abf99be
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/inheritence/InheritanceTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.inheritence;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.a.IA;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.b.IB;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.c.C;
+import org.apache.felix.ipojo.runtime.core.components.inheritance.d.D;
+import org.junit.Assert;
+import org.junit.Test;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
+
+/**
+ * TODO This test does not work on KF, for an unknown reason.
+ */
+public class InheritanceTest extends Common {
+
+ @Override
+ public boolean deployTestBundle() {
+ return false;
+ }
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Option[] options = super.config();
+
+ return OptionUtils.combine(
+ options,
+ streamBundle(
+ // Bundle A
+ TinyBundles.bundle()
+ .add(IA.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "A")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.components.inheritance.a")
+ .build(withBnd())
+ ),
+ streamBundle(
+ // Bundle B
+ TinyBundles.bundle()
+ .add(IB.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "B")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.components.inheritance.a")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.runtime.core.components" +
+ ".inheritance.b")
+ .build(withBnd())
+ ),
+ streamBundle(
+ // Bundle C
+ TinyBundles.bundle()
+ .add(C.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "C")
+ .set(Constants.IMPORT_PACKAGE,
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.a, " +
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.b")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/inheritance/provider" +
+ ".xml")))
+ ),
+ streamBundle(
+ // Bundle D
+ TinyBundles.bundle()
+ .add(D.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME, "D")
+ .set(Constants.IMPORT_PACKAGE,
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.a, " +
+ "org.apache.felix.ipojo.runtime.core.components.inheritance.b")
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources/inheritance/cons" +
+ ".xml")))
+ )
+
+
+ );
+ }
+
+ @Test
+ public void testDeploy() {
+ if (isKnopflerfish()) {
+ System.out.println("Test disabled on knopflerfish");
+ return;
+ }
+
+ Bundle[] bundles = bc.getBundles();
+ for (Bundle bundle : bundles) {
+ Assert.assertEquals(bundle.getSymbolicName() + " is not active", Bundle.ACTIVE, bundle.getState());
+ }
+
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=c)", 10000);
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=d)", 10000);
+
+ Object[] arch = osgiHelper.getServiceObjects(Architecture.class.getName(), null);
+ for (Object o : arch) {
+ Architecture a = (Architecture) o;
+ if (a.getInstanceDescription().getState() != ComponentInstance.VALID) {
+ Assert.fail("Instance " + a.getInstanceDescription().getName() + " not valid : " + a.getInstanceDescription().getDescription());
+ }
+ }
+ }
+
+ @Test
+ public void testArchitecture() {
+ if (isKnopflerfish()) {
+ System.out.println("Test disabled on knopflerfish");
+ return;
+ }
+
+ osgiHelper.waitForService(Architecture.class.getName(), "(architecture.instance=d)", 10000);
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(Architecture.class.getName(), "d");
+ Assert.assertNotNull(ref);
+
+ Architecture arch = (Architecture) osgiHelper.getRawServiceObject(ref);
+
+ System.out.println(arch.getInstanceDescription().getDescription());
+
+ Assert.assertEquals(ComponentInstance.VALID, arch.getInstanceDescription().getState());
+ DependencyDescription dd = getDependency(arch, "org.apache.felix.ipojo.runtime.core.components.inheritance.b.IB");
+
+ Assert.assertTrue(!dd.getServiceReferences().isEmpty());
+
+ ServiceReference dref = (ServiceReference) dd.getServiceReferences().get(0);
+ Assert.assertEquals(dref.getBundle().getSymbolicName(), "C");
+
+ }
+
+ private DependencyDescription getDependency(Architecture arch, String id) {
+ DependencyHandlerDescription hd = (DependencyHandlerDescription) arch.getInstanceDescription().getHandlerDescription("org.apache.felix.ipojo:requires");
+ Assert.assertNotNull(hd);
+ for (DependencyDescription dd : hd.getDependencies()) {
+ if (dd.getId().equals(id)) {
+ return dd;
+ }
+ }
+ Assert.fail("Dependency " + id + " not found");
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategy2Test.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategy2Test.java
new file mode 100644
index 0000000..15f1516
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategy2Test.java
@@ -0,0 +1,228 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
+public class CustomStrategy2Test extends Common {
+
+
+ private ComponentInstance cons1, cons2, prov;
+ private ComponentInstance cons3, prov2;
+
+ @Before
+ public void setUp() {
+ cons1 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons1 invalid", ComponentInstance.INVALID, cons1.getState());
+ cons2 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons2 invalid", ComponentInstance.INVALID, cons2.getState());
+ prov = ipojoHelper.createComponentInstance("PSS-FooProviderType-Custom2");
+ prov2 = ipojoHelper.createComponentInstance("PSS-FooBarProviderType-Custom2");
+ cons3 = ipojoHelper.createComponentInstance("PSS-ConsBar");
+ prov2.stop();
+ prov.stop();
+ }
+
+ @After
+ public void tearDown() {
+ reset();
+ }
+
+
+ private void reset() {
+ FooProviderType1.resetIds();
+ FooBarProviderType1.resetIds();
+ }
+
+ private void checkCreatedObjects(ComponentInstance ci, int expected) {
+ assertEquals("Number of created objects", expected, ((PrimitiveInstanceDescription) ci.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ @Test
+ public void testOneService() {
+ prov.start();
+ cons2.stop();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov.getInstanceName());
+ assertNotNull("Service available", ref);
+ checkCreatedObjects(prov, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov, 1);
+
+
+ // Step 2 : create a second consumer
+ cons2.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov, 2);
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ System.out.println("cons2 stopping");
+ cons2.stop();
+ System.out.println("cons2 stopped");
+ checkCreatedObjects(prov, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+ @Test
+ public void testObjectCreation() {
+ prov.start();
+
+ // The two consumers are started and use their own objects.
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ FooService fscons1 = (FooService) props.get("object");
+
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ FooService fscons2 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Stop the provider
+ prov.stop();
+ // Cons1 and 2 are invalid.
+ assertEquals("Cons1 invalidity", ComponentInstance.INVALID, cons1.getState());
+ assertEquals("Cons2 invalidity", ComponentInstance.INVALID, cons2.getState());
+
+ // No object created in prov
+ checkCreatedObjects(prov, 0);
+
+ // Restart the provider
+ prov.start();
+
+ // Consumers are valid.
+ assertEquals("Cons1 validity", ComponentInstance.VALID, cons1.getState());
+ assertEquals("Cons2 validity", ComponentInstance.VALID, cons2.getState());
+
+ // Check objects
+ refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ props = cs_cons1.getProps();
+ Object fscons3 = (FooService) props.get("object");
+
+ refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ props2 = cs_cons2.getProps();
+ Object fscons4 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons3, fscons4);
+ assertNotSame("Two new objects - 1", fscons3, fscons1);
+ assertNotSame("Two new objects - 2", fscons4, fscons2);
+
+ }
+
+ @Test
+ public void testTwoServices() {
+ cons3.stop();
+ prov2.start();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov2.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", ref);
+ ServiceReference refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", refBar);
+ checkCreatedObjects(prov2, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov2, 1);
+
+
+ // Step 2 : create a second consumer
+ cons3.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons3.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov2, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ cons3.stop();
+ checkCreatedObjects(prov2, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategyTest.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategyTest.java
new file mode 100644
index 0000000..72f2652
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/CustomStrategyTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
+public class CustomStrategyTest extends Common {
+
+
+ private ComponentInstance cons1, cons2, prov;
+ private ComponentInstance cons3, prov2;
+
+ @Before
+ public void setUp() {
+ cons1 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons1 invalid", ComponentInstance.INVALID, cons1.getState());
+ cons2 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons2 invalid", ComponentInstance.INVALID, cons2.getState());
+ prov = ipojoHelper.createComponentInstance("PSS-FooProviderType-Custom");
+ prov2 = ipojoHelper.createComponentInstance("PSS-FooBarProviderType-Custom");
+ cons3 = ipojoHelper.createComponentInstance("PSS-ConsBar");
+ prov2.stop();
+ prov.stop();
+ }
+
+ @After
+ public void tearDown() {
+ reset();
+ }
+
+
+ private void reset() {
+ FooProviderType1.resetIds();
+ FooBarProviderType1.resetIds();
+ }
+
+ private void checkCreatedObjects(ComponentInstance ci, int expected) {
+ assertEquals("Number of created objects", expected, ((PrimitiveInstanceDescription) ci.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ @Test
+ public void testOneService() {
+ prov.start();
+ cons2.stop();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov.getInstanceName());
+ assertNotNull("Service available", ref);
+ checkCreatedObjects(prov, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov, 1);
+
+
+ // Step 2 : create a second consumer
+ cons2.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov, 2);
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ System.out.println("cons2 stopping");
+ cons2.stop();
+ System.out.println("cons2 stopped");
+ checkCreatedObjects(prov, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+ @Test
+ public void testObjectCreation() {
+ prov.start();
+
+ // The two consumers are started and use their own objects.
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ FooService fscons1 = (FooService) props.get("object");
+
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ FooService fscons2 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Stop the provider
+ prov.stop();
+ // Cons1 and 2 are invalid.
+ assertEquals("Cons1 invalidity", ComponentInstance.INVALID, cons1.getState());
+ assertEquals("Cons2 invalidity", ComponentInstance.INVALID, cons2.getState());
+
+ // No object created in prov
+ checkCreatedObjects(prov, 0);
+
+ // Restart the provider
+ prov.start();
+
+ // Consumers are valid.
+ assertEquals("Cons1 validity", ComponentInstance.VALID, cons1.getState());
+ assertEquals("Cons2 validity", ComponentInstance.VALID, cons2.getState());
+
+ // Check objects
+ refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ props = cs_cons1.getProps();
+ Object fscons3 = (FooService) props.get("object");
+
+ refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ props2 = cs_cons2.getProps();
+ Object fscons4 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons3, fscons4);
+ assertNotSame("Two new objects - 1", fscons3, fscons1);
+ assertNotSame("Two new objects - 2", fscons4, fscons2);
+
+ }
+
+ @Test
+ public void testTwoServices() {
+ cons3.stop();
+ prov2.start();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov2.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", ref);
+ ServiceReference refBar;
+ refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", refBar);
+ checkCreatedObjects(prov2, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov2, 1);
+
+
+ // Step 2 : create a second consumer
+ cons3.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons3.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov2, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ cons3.stop();
+ checkCreatedObjects(prov2, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/PerInstanceStrategyTest.java b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/PerInstanceStrategyTest.java
new file mode 100644
index 0000000..91bb2f3
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-providing-test/src/test/java/org/apache/felix/ipojo/runtime/core/strategies/PerInstanceStrategyTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.strategies;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
+import org.apache.felix.ipojo.runtime.core.Common;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooBarProviderType1;
+import org.apache.felix.ipojo.runtime.core.components.strategies.FooProviderType1;
+import org.apache.felix.ipojo.runtime.core.services.BarService;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
+public class PerInstanceStrategyTest extends Common {
+
+ private ComponentInstance cons1, cons2, prov;
+ private ComponentInstance cons3, prov2;
+
+ @Before
+ public void setUp() {
+ cons1 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons1 invalid", ComponentInstance.INVALID, cons1.getState());
+ cons2 = ipojoHelper.createComponentInstance("PSS-Cons");
+ assertEquals("cons2 invalid", ComponentInstance.INVALID, cons2.getState());
+ prov = ipojoHelper.createComponentInstance("PSS-FooProviderType-Instance");
+ prov2 = ipojoHelper.createComponentInstance("PSS-FooBarProviderType-Instance");
+ cons3 = ipojoHelper.createComponentInstance("PSS-ConsBar");
+ prov2.stop();
+ prov.stop();
+ }
+
+ @After
+ public void tearDown() {
+ reset();
+ }
+
+
+ private void reset() {
+ FooProviderType1.resetIds();
+ FooBarProviderType1.resetIds();
+ }
+
+ private void checkCreatedObjects(ComponentInstance ci, int expected) {
+ assertEquals("Number of created objects", expected, ((PrimitiveInstanceDescription) ci.getInstanceDescription()).getCreatedObjects().length);
+ }
+
+ @Test
+ public void testOneService() {
+ prov.start();
+ cons2.stop();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov.getInstanceName());
+ assertNotNull("Service available", ref);
+ checkCreatedObjects(prov, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov, 1);
+
+
+ // Step 2 : create a second consumer
+ cons2.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov, 2);
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ System.out.println("cons2 stopping");
+ cons2.stop();
+ System.out.println("cons2 stopped");
+ checkCreatedObjects(prov, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+ @Test
+ public void testObjectCreation() {
+ prov.start();
+
+ // The two consumers are started and use their own objects.
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ FooService fscons1 = (FooService) props.get("object");
+
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ FooService fscons2 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Stop the provider
+ prov.stop();
+ // Cons1 and 2 are invalid.
+ assertEquals("Cons1 invalidity", ComponentInstance.INVALID, cons1.getState());
+ assertEquals("Cons2 invalidity", ComponentInstance.INVALID, cons2.getState());
+
+ // No object created in prov
+ checkCreatedObjects(prov, 0);
+
+ // Restart the provider
+ prov.start();
+
+ // Consumers are valid.
+ assertEquals("Cons1 validity", ComponentInstance.VALID, cons1.getState());
+ assertEquals("Cons2 validity", ComponentInstance.VALID, cons2.getState());
+
+ // Check objects
+ refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ props = cs_cons1.getProps();
+ Object fscons3 = (FooService) props.get("object");
+
+ refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ props2 = cs_cons2.getProps();
+ Object fscons4 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons3, fscons4);
+ assertNotSame("Two new objects - 1", fscons3, fscons1);
+ assertNotSame("Two new objects - 2", fscons4, fscons2);
+
+ }
+
+ @Test
+ public void testTwoServices() {
+ cons3.stop();
+ prov2.start();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov2.getState());
+ ServiceReference ref = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", ref);
+ ServiceReference refBar = ipojoHelper.getServiceReferenceByName(BarService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", refBar);
+ checkCreatedObjects(prov2, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) osgiHelper.getRawServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov2, 1);
+
+
+ // Step 2 : create a second consumer
+ cons3.start();
+ ServiceReference refcons2 = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), cons3.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) osgiHelper.getRawServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov2, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ cons3.stop();
+ checkCreatedObjects(prov2, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/pom.xml b/ipojo/runtime/core-it/pom.xml
new file mode 100644
index 0000000..3194397
--- /dev/null
+++ b/ipojo/runtime/core-it/pom.xml
@@ -0,0 +1,430 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Runtime Project ~ Core Integration Tests</name>
+ <packaging>pom</packaging>
+
+ <properties>
+ <!-- Tests are enabled only when the 'test' profile is activated -->
+ <skipTestExecution>true</skipTestExecution>
+
+ <exam.version>3.0.1</exam.version>
+ <url.version>1.5.1</url.version>
+
+ <felix.version>4.4.1</felix.version>
+ <equinox.version>3.10.0.v20140606-1445</equinox.version>
+ <knoperflerfish.version>7.1.2</knoperflerfish.version>
+
+ <manipulator.version>1.12.1</manipulator.version>
+ </properties>
+
+ <modules>
+ <module>ipojo-core-annotations-test</module>
+ <module>ipojo-core-bad-configuration-test</module>
+ <module>ipojo-core-configuration-admin-test</module>
+ <module>ipojo-core-configuration-processor-test</module>
+ <module>ipojo-core-configuration-test</module>
+ <module>ipojo-core-declaration-test</module>
+ <module>ipojo-core-external-handlers-test</module>
+ <module>ipojo-core-factory-test</module>
+ <module>ipojo-core-factory-version-test</module>
+ <module>ipojo-core-handler-test</module>
+ <module>ipojo-core-lifecycle-callback-test</module>
+ <module>ipojo-core-lifecycle-controller-test</module>
+ <module>ipojo-core-logger-test</module>
+ <module>ipojo-core-service-dependency-optional-test</module>
+ <module>ipojo-core-service-dependency-policies</module>
+ <module>ipojo-core-service-dependency-proxies</module>
+ <module>ipojo-core-service-dependency-test</module>
+ <module>ipojo-core-service-dependency-timeout-test</module>
+ <module>ipojo-core-service-dependency-interceptor-test</module>
+ <module>ipojo-core-service-providing-test</module>
+ <module>ipojo-core-context-injection-test</module>
+ <module>ipojo-api-test</module>
+ <module>ipojo-compatibility-test</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.14.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <!-- TIME_FACTOR can be set from the command line with -DTIME_FACTOR=9-->
+ <TIME_FACTOR>${TIME_FACTOR}</TIME_FACTOR>
+ <!-- Defined by the profiles -->
+ <pax.exam.framework>${pax.exam.framework}</pax.exam.framework>
+ </systemPropertyVariables>
+ <skipTests>${skipTestExecution}</skipTests>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/*.iml</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ </build>
+
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.9</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>tinybundles-ipojo</artifactId>
+ <version>0.3.0</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>asm</groupId>
+ <artifactId>asm-all</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>${manipulator.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <version>1.8.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.testing</groupId>
+ <artifactId>osgi-helpers</artifactId>
+ <version>0.6.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin</artifactId>
+ <!--
+ We use the released version as we don't really have to do any behavioral test on the handler in the core
+ test.
+ -->
+ <version>1.8.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.log</artifactId>
+ <version>1.0.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-wrap</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.easytesting</groupId>
+ <artifactId>fest-assert</artifactId>
+ <version>1.4</version>
+ </dependency>
+
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>default</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <properties>
+ <pax.exam.framework>none</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>knopflerfish</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>knopflerfish</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>knopflerfish</pax.exam.framework>
+ </properties>
+ <repositories>
+ <repository>
+ <id>knopflerfish-releases</id>
+ <url>http://www.knopflerfish.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.knopflerfish</groupId>
+ <artifactId>framework</artifactId>
+ <version>${knoperflerfish.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <!-- must be after KF -->
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>equinox</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>equinox</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>equinox</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>${equinox.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <!-- must be after equinox -->
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>felix</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>pax.exam.framework</name>
+ <value>felix</value>
+ </property>
+ </activation>
+ <properties>
+ <pax.exam.framework>felix</pax.exam.framework>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>${felix.version}</version>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>test</id>
+ <properties>
+ <skipTestExecution>false</skipTestExecution>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/ipojo/runtime/core-it/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/core-it/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/runtime/core-it/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/runtime/core/changelog.txt b/ipojo/runtime/core/changelog.txt
new file mode 100644
index 0000000..0d7fa86
--- /dev/null
+++ b/ipojo/runtime/core/changelog.txt
@@ -0,0 +1,398 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.10.0 to 1.10.1
+-----------------------------
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3742] - Implementing class fails to load unless super interface's (interface extended by implemented interface) package is imported.
+ * [FELIX-3789] - Deadlock due to synchronization on INSTANCE_NAME
+ * [FELIX-3819] - The export directive of iPOJO is wrong
+
+Changes from the 1.8.2 to 1.8.4
+--------------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3500] - InstanceManager concurrency issue: "A methodID cannot be associated with a method from the POJO class"
+ * [FELIX-3501] - IPojo FactoryStateListener doesn't get notified while stopping factory
+ * [FELIX-3545] - Memory leak when unregistering a component used by an aggregate dependency with an unbind callback
+ * [FELIX-3548] - Concurrent access during startup
+ * [FELIX-3567] - iPOJO Configuration Handler should not reuse the dictionary object from the configuration admin
+ * [FELIX-3576] - iPOJO fails when using constructor injection and expecting BundleContext in ctor
+ * [FELIX-3599] - Problem with 'subservice action="instantiate"' in ipojo composite
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+ * [FELIX-3672] - Potential Concurrent Modification Exception when a bundle is stopped
+
+** Improvement
+ * [FELIX-3560] - Extensions to IPojo's Factory and ComponentInstance documentation for custom handlers
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+** Bug
+ * [FELIX-2893] - Properties are not propagate to service by default
+ * [FELIX-2902] - Service properties added by propagation overrides already existing properties
+ * [FELIX-2907] - Problem calling _setInstanceManager on guice enhanced classe
+ * [FELIX-2981] - Unable to remove configuration properties using iPOJO's configuration handler
+ * [FELIX-2989] - Using a Service Controller set to true can trigger a service registration-unregistration-registration sequence
+ * [FELIX-2995] - The service properties are updated despite there is no changes
+ * [FELIX-3009] - Abstract classes as service specifications generates warnings at runtime
+ * [FELIX-3075] - Change to ServiceController status in current trunk does not re-register service
+ * [FELIX-3172] - Error when calling BundleContext.register(Class, Object, Dictionary)
+ * [FELIX-3192] - Service properties are not updated if the properties were already propagated
+ * [FELIX-3271] - On KF, the Instance singleton strategy throws an UnsupportedOperationException when stopping
+ * [FELIX-3323] - Ipojo composite throw ClassCastException when configuration is updated thru ConfigAdmin
+ * [FELIX-3356] - Objectweb ASM Clashes with IPojo
+ * [FELIX-3374] - Use of java.lang.Properties in iPOJO Core
+
+** Improvement
+ * [FELIX-3036] - Add IPOJO-Components header support
+ * [FELIX-3081] - Integrate the online-manipulator in iPOJO Core
+ * [FELIX-3144] - Method interceptors should receive Method or Constructor objects
+ * [FELIX-3155] - Allow identifying iPojo extensions by a namespace qualified name
+ * [FELIX-3190] - iPOJO Factories doesn't give access to the complete Metadata model
+ * [FELIX-3252] - Merge the online manipulator into iPOJO Core
+ * [FELIX-3326] - Accessing IPojo-Component's all inherited classes and all implemented interfaces in PrimitiveTypeDescription
+
+** New Feature
+ * [FELIX-2932] - Allows disabling the asynchronous processing in the iPOJO Extender
+
+Changes from the 1.6.8 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2694] - Instance state not recomputed after reconfiguration when the instance is stopped
+ * [FELIX-2716] - [iPOJO] Failure when creating proxies for classes in java.* packages
+
+** Improvement
+ * [FELIX-2781] - Expose the implementation class as service when no interfaces are found in the hierarchy
+ * [FELIX-1424] - Constructor Injection
+ * [FELIX-1428] - Constructor injection of Configuration properties
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+ * [FELIX-2620] - Change iPojo annotation parameters to follow java naming conventions
+ * [FELIX-2621] - Rename annotations to remove collisions
+ * [FELIX-2622] - Support static service properties that are not mirrored into fields
+ * [FELIX-2688] - iPojo "requires.filters" - Array object instead of Dictionary object
+ * [FELIX-2705] - Provide a way to extend the logger strategy
+ * [FELIX-2742] - Constructor injection of service dependencies
+ * [FELIX-2744] - Add annotations to the maven-ipojo-plugin archetype
+
+Changes from the 1.6.6 to 1.6.8
+-------------------------------
+** Improvement
+ * [FELIX-2688] - iPojo "requires.filters" - Array object instead of Dictionary object
+ * [FELIX-2705] - Provide a way to extend the logger strategy
+
+** Bug
+ * [FELIX-2685] - Wrong Element name when XML namespace contains ':'
+ * [FELIX-2694] - Instance state not recomputed after reconfiguration when the instance is stopped
+
+Changes from the 1.6.4 to 1.6.6
+-------------------------------
+** Improvement
+ * [FELIX-2594] - Have a way to create new custom iPojo handler without having to specify a handler usage
+ * [FELIX-2623] - @Update annotated methods should not require a Dictionary parameter
+
+** Bug
+ * [FELIX-2580] - iPOJO failed to create proxies on service which are not interface
+ * [FELIX-2596] - DependencyHandler.onObjectCreation throws NPE when bundle is refreshed
+ * [FELIX-2603] - wrong behavior of InstanceManager.onSet(..) method
+ * [FELIX-2636] - Cannot control the validity of an iPOJO instance using a configuration property
+
+Changes from the 1.6.2 to 1.6.4
+-------------------------------
+** Improvement
+ * [FELIX-2420] - Enum support for @Property annotation
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+ * [FELIX-2472] - Proxies should throw a runtime exception instead of a null pointer exception
+
+** Bug
+ * [FELIX-2561] - Properties set as required instead of optional in the component type descriptions
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Bug
+ * [FELIX-2308] - getService is called during the unregistration of a service.
+ * [FELIX-2309] - Potential NPE when a service has abruptly in the smart proxies.
+ * [FELIX-2323] - Unbind method should not be called during the invalidation process if the invalidation does not come from a service departure.
+
+** Improvement
+ * [FELIX-2296] - Access to ServiceReference in iPOJO service.
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1533] - Potential deadlock when stopping the underlying OSGi framework
+ * [FELIX-1965] - iPojo component is made available regardless of exception during validate
+ * [FELIX-2014] - Potential ClassCastException when a service property does not receive a value and is used in the constructor
+ * [FELIX-2019] - The Property value is 'null' in the Architecture description, while the value is well assigned to the component's field.
+ * [FELIX-2052] - Handler require callback are not called if the service (required) is registered before the instance of the handler has been started.
+ * [FELIX-2093] - iPOJO doesn't always use the correct class loader
+
+** Improvement
+ * [FELIX-1425] - Service Proxy Mode
+ * [FELIX-1426] - Service injection with Dynamic Proxies
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1532] - Be able to set the iPOJO Log Level from BND
+ * [FELIX-1741] - Allows the configuration handler description to retrieve the managed service PID
+ * [FELIX-1854] - Allows instances to directly declares service.* properties (pid, ranking, vendor, description)
+ * [FELIX-1885] - Ease CreationStrategy & iPOJOServiceFactory usage
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+** New Feature
+ * [FELIX-2132] - Provides a way to control service exposition from the implementation class
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-985] - iPOJO analyzes already installed bundle by holding a lock
+ * [FELIX-1002] - iPOJO Static binding policy is not compliant with the Declarative Service static binding policy.
+ * [FELIX-1318] - Case mismatch problem of iPOJO custom handler name
+** Improvement
+ * Update parent pom
+ * [FELIX-936] - Allowing publishing class as services
+ * [FELIX-966] - iPOJO: Better error reporting when getPojoObject return null
+ * [FELIX-982] - Declare iPOJO as a singleton bundle to avoid multiple version of the runtime at the same time
+ * [FELIX-1114] - callback after configuration change needed
+ * [FELIX-1163] - Improve error message when an array cannot be created due to a classloading issue
+ * [FELIX-1182] - iPOJO - reconfiguration : get all properties with the update callback
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-797] - Composite Architecture contains duplicate instances
+ * [FELIX-803] - iPOJO Core schema needs to be fixed
+ * [FELIX-805] - Instance not created if the factory becomes valid later
+ * [FELIX-866] - iPOJO Provides 'interface' attribute should be 'specifications'
+
+** Improvement
+ * [FELIX-787] - iPOJO logger log messages inside the log service and print them
+ * [FELIX-796] - Allows enabling/disabling the internal event dispatcher
+ * [FELIX-801] - Support service properties injection in bind/unbind callbacks
+ * [FELIX-815] - Support optional properties
+ * [FELIX-816] - Support comparator attribute with any service binding policy
+ * [FELIX-818] - Implement the ServiceReference compareTo method
+ * [FELIX-853] - Provide new service object creation strategies
+ * New introspection API
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Bug
+ * [FELIX-557] - Factories still living when a primitive component does not have its manipulation metadata
+ * [FELIX-632] - Component are set to immediate despite they are already immediate
+ * [FELIX-635] - Simplify factory name computation
+ * [FELIX-628] - Architecture service should not publish the instance.name property
+ * [FELIX-621] - Instances not disposed when instances creation failed
+
+** Improvement
+ * [FELIX-552] - ClassCastException when using services as dynamic proxies
+ * [FELIX-555] - Error message in the iPOJO Extender could be more accurate when failing to get the bundle context
+ * [FELIX-558] - Non caught NoClassDefFoundError when the instantiation of a Nullable object failed
+ * [FELIX-603] - Improve iPOJO Arch service dependency description
+ * [FELIX-626] - Allow specifying instance configuration containing empty dictionaries
+ * [FELIX-629] - Allows instance configuration to declares complex properties
+ * [FELIX-631] - Immediate Component Detection
+ * [FELIX-633] - Factory creation should be done in another thread
+ * [FELIX-634] - Improve error handling
+ * [FELIX-655] - Add a 'from' attribute in the service dependencies
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-683] - Supporting lists and vectors in the service dependency management
+ * [FELIX-686] - Supporting collections and set in the service dependency management
+ * [FELIX-688] - Better error reporting when an instance creation failed
+ * [FELIX-689] - Instance 'name' property should become 'instance.name'
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+ * [FELIX-732] - Duplicate instance created of a managed service
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/runtime/core/obr.xml b/ipojo/runtime/core/obr.xml
new file mode 100644
index 0000000..00a9cea
--- /dev/null
+++ b/ipojo/runtime/core/obr.xml
@@ -0,0 +1,44 @@
+<!--
+ 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.
+-->
+<obr>
+ <capability name="ipojo.handler">
+ <p n="name" v="controller"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="callback"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="requires"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="provides"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="properties"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+ <capability name="ipojo.handler">
+ <p n="name" v="architecture"/>
+ <p n="namespace" v="org.apache.felix.ipojo"/>
+ </capability>
+</obr>
\ No newline at end of file
diff --git a/ipojo/runtime/core/pom.xml b/ipojo/runtime/core/pom.xml
new file mode 100644
index 0000000..9deebc4
--- /dev/null
+++ b/ipojo/runtime/core/pom.xml
@@ -0,0 +1,375 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO</name>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <properties>
+ <!--
+ 1.8.2:
+ * change in the MethodInterceptor interface (FELIX-3144)
+ * change in the Factory interface (FELIX-3190)
+
+ 1.8.4:
+ * change in ComponentTypeDescription (FELIX-3560)
+
+ 1.10.0:
+ * next minor version
+
+ 1.11.0:
+ * several changes - annotations, enum, refactoring of the dependency handler
+
+ 1.11.1:
+ * minor changes such as synchronization protocols
+
+ 1.11.2:
+ * add the InstanceBundleContextAware interface
+
+ 1.12.0:
+ * change in the manipulator (frame / java 8 support). Despite it's not really an API change, it breaks
+ the compatibility.
+
+ 1.12.1:
+ * small changes in the API
+ -->
+ <ipojo.package.version>1.12.1</ipojo.package.version>
+ <ipojo.extender.version>1.12.1</ipojo.extender.version>
+ </properties>
+
+ <description>
+ iPOJO Core bundle
+ </description>
+ <url>
+ http://ipojo.org
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.3.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <!-- We use the FilterImpl of Felix in tests -->
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>5.0.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easytesting</groupId>
+ <artifactId>fest-assert</artifactId>
+ <version>1.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.0</version>
+ <configuration>
+ <target>1.5</target>
+ <source>1.5</source>
+ <testTarget>1.5</testTarget>
+ <testSource>1.5</testSource>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>package-main-artifact</id>
+ <phase>package</phase>
+ <goals>
+ <goal>bundle</goal>
+ </goals>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO</Bundle-Name>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-SymbolicName>org.apache.felix.ipojo;singleton:=true</Bundle-SymbolicName>
+ <Bundle-Description>iPOJO Core Framework</Bundle-Description>
+ <Bundle-Activator>org.apache.felix.ipojo.extender.internal.Extender</Bundle-Activator>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo.html
+ </Bundle-DocURL>
+ <IPOJO-Extension>
+ component:org.apache.felix.ipojo.ComponentFactory,
+ handler:org.apache.felix.ipojo.HandlerManagerFactory
+ </IPOJO-Extension>
+ <Import-Package>
+ org.osgi.framework;version="[1.3,2)", <!-- To support KF 2 -->
+ org.osgi.framework.wiring;version="[1.0,2.0)";resolution:=optional,
+ org.osgi.service.cm;version="[1.3,2)",
+ org.osgi.service.log;version="[1.3,2)",
+ org.osgi.util.tracker;version="[1.4,2)", <!-- BundleTracker is in R4.2 -->
+ !sun.io,
+ !net.sourceforge.cobertura.*, <!-- To support code coverage -->
+ !org.objectweb.asm.signature,
+ !org.objectweb.asm.tree
+ </Import-Package>
+ <Private-Package>
+ org.apache.felix.ipojo.handlers.architecture,
+ org.apache.felix.ipojo.handlers.lifecycle.callback,
+ org.apache.felix.ipojo.handlers.lifecycle.controller,
+ org.apache.felix.ipojo.handlers.context,
+ org.apache.felix.ipojo.extender.internal*,
+ org.objectweb.asm;-split-package:=merge-last,
+ org.objectweb.asm.commons;-split-package:=merge-last,
+ org.apache.felix.ipojo.metadata,
+ org.apache.felix.ipojo.dependency.impl
+ </Private-Package>
+ <Export-Package>
+ org.apache.felix.ipojo; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.configuration; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.metadata; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.architecture; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender;
+ version="${ipojo.package.version}";-split-package:=merge-first,
+ org.apache.felix.ipojo.extender.builder; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender.queue; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender.queue.debug; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.parser; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.util; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.dependency; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.providedservice.*; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.configuration; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.context; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.dependency.interceptors; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.annotations; version="${ipojo.package.version}",
+ <!-- Compendium packages -->
+ org.osgi.service.cm; version=1.3,
+ org.osgi.service.log; version=1.3
+ </Export-Package>
+
+ <!-- OSGi Extender Namespace -->
+ <Provide-Capability>osgi.extender;
+ osgi.extender="org.apache.felix.ipojo";
+ version:Version="${ipojo.extender.version}"
+ </Provide-Capability>
+ <_donotcopy>(CVS|.svn|.+.bak|~.+|metadata.xml)</_donotcopy>
+ </instructions>
+ </configuration>
+ </execution>
+ <execution>
+ <id>package-bare-artifact</id>
+ <phase>package</phase>
+ <goals>
+ <goal>bundle</goal>
+ </goals>
+ <configuration>
+ <classifier>bare</classifier>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO</Bundle-Name>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-SymbolicName>org.apache.felix.ipojo;singleton:=true</Bundle-SymbolicName>
+ <Bundle-Description>iPOJO Core Framework</Bundle-Description>
+ <Bundle-Activator>org.apache.felix.ipojo.extender.internal.Extender</Bundle-Activator>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo.html
+ </Bundle-DocURL>
+ <IPOJO-Extension>
+ component:org.apache.felix.ipojo.ComponentFactory,
+ handler:org.apache.felix.ipojo.HandlerManagerFactory
+ </IPOJO-Extension>
+ <Import-Package>
+ org.osgi.framework;version="[1.3,2)", <!-- To support KF 2 -->
+ org.osgi.framework.wiring;version="[1.0,2.0)";resolution:=optional,
+ org.osgi.service.cm;version="[1.3,2)",
+ org.osgi.service.log;version="[1.3,2)",
+ org.osgi.util.tracker;version="[1.4,2)", <!-- BundleTracker is in R4.2 -->
+ !sun.io,
+ !net.sourceforge.cobertura.*, <!-- To support code coverage -->
+ !org.objectweb.asm.signature,
+ !org.objectweb.asm.tree
+ </Import-Package>
+ <Private-Package>
+ org.apache.felix.ipojo.handlers.architecture,
+ org.apache.felix.ipojo.handlers.lifecycle.callback,
+ org.apache.felix.ipojo.handlers.lifecycle.controller,
+ org.apache.felix.ipojo.handlers.context,
+ org.apache.felix.ipojo.extender.internal*,
+ org.objectweb.asm;-split-package:=merge-last,
+ org.objectweb.asm.commons;-split-package:=merge-last,
+ org.apache.felix.ipojo.metadata,
+ org.apache.felix.ipojo.dependency.impl
+ </Private-Package>
+ <Export-Package>
+ org.apache.felix.ipojo; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.configuration; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.metadata; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.architecture; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender;
+ version="${ipojo.package.version}";-split-package:=merge-first,
+ org.apache.felix.ipojo.extender.builder; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender.queue; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.extender.queue.debug; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.parser; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.util; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.dependency; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.providedservice.*; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.handlers.configuration; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.context; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.dependency.interceptors; version="${ipojo.package.version}",
+ org.apache.felix.ipojo.annotations; version="${ipojo.package.version}"
+ <!-- the bare bundle does not includes any packages form the compendium -->
+ </Export-Package>
+
+ <!-- OSGi Extender Namespace -->
+ <Provide-Capability>osgi.extender;
+ osgi.extender="org.apache.felix.ipojo";
+ version:Version="${ipojo.extender.version}"
+ </Provide-Capability>
+ <_donotcopy>(CVS|.svn|.+.bak|~.+|metadata.xml)</_donotcopy>
+ </instructions>
+ </configuration>
+ </execution>
+ </executions>
+
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.12.0</version>
+ <executions>
+ <execution>
+ <id>main-artifact-manipulation</id>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ </configuration>
+ </execution>
+ <execution>
+ <id>bare-artifact-manipulation</id>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <!--<classifier>bare</classifier>-->
+ <input-classifier>bare</input-classifier>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- check src only (except remote resources additions) -->
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>src/main/appended-resources/**</exclude>
+ <exclude>**/manipulation/MANIFEST.MF</exclude> <!-- This file is used by tests -->
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.7</version>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java15</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/runtime/core/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/core/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..844c77e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,21 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/core/src/main/appended-resources/META-INF/LICENSE b/ipojo/runtime/core/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..4915a4d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,42 @@
+
+
+APACHE FELIX iPOJO Core:
+
+The Apache Felix iPOJO Core includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the ASM component:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/ipojo/runtime/core/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/core/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..4ae983c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,8 @@
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
new file mode 100644
index 0000000..660ceba
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
@@ -0,0 +1,461 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.Tracker;
+import org.apache.felix.ipojo.util.TrackerCustomizer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.security.ProtectionDomain;
+import java.util.*;
+
+/**
+ * The component factory manages component instance objects. This management
+ * consists to create and manage component instances build with the current
+ * component factory. If the factory is public a {@link Factory} service is exposed.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.apache.felix.ipojo.Factory
+ * @see org.apache.felix.ipojo.IPojoFactory
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer
+ */
+public class ComponentFactory extends IPojoFactory implements TrackerCustomizer {
+
+ /**
+ * System property set to automatically attach primitive handlers to primitive
+ * component types.
+ * The value is a String parsed as a list (comma separated). Each element is
+ * the fully qualified name of the handler <code>namespace:name</code>.
+ */
+ public static final String HANDLER_AUTO_PRIMITIVE = "org.apache.felix.ipojo.handler.auto.primitive";
+ /**
+ * The tracker used to track required handler factories.
+ * Immutable once set.
+ */
+ protected Tracker m_tracker;
+ /**
+ * The class loader to delegate classloading.
+ * Immutable once set.
+ */
+ private FactoryClassloader m_classLoader;
+ /**
+ * The component implementation class.
+ * (manipulated byte array)
+ */
+ private byte[] m_clazz;
+ /**
+ * The component implementation qualified class name.
+ * Immutable once set.
+ * This attribute is set during the creation of the factory.
+ */
+ private String m_classname;
+ /**
+ * The manipulation metadata of the implementation class.
+ * Immutable once set.
+ * This attribute is set during the creation of the factory.
+ */
+ private PojoMetadata m_manipulation;
+ /**
+ * A flag enabling / disabling the use of the Factory classloader to define the class.
+ * This flag must be enabled if the component class was manipulated on the fly.
+ */
+ private boolean m_useFactoryClassloader = false;
+
+ /**
+ * Creates a instance manager factory.
+ * The class is given in parameter. The component type is not a composite.
+ *
+ * @param context the bundle context
+ * @param clazz the component class
+ * @param element the metadata of the component
+ * @throws ConfigurationException if the element describing the factory is malformed.
+ */
+ public ComponentFactory(BundleContext context, byte[] clazz, Element element) throws ConfigurationException {
+ this(context, element);
+ m_clazz = clazz;
+ }
+
+ /**
+ * Creates a instance manager factory.
+ *
+ * @param context the bundle context
+ * @param element the metadata of the component to create
+ * @throws ConfigurationException if element describing the factory is malformed.
+ */
+ public ComponentFactory(BundleContext context, Element element) throws ConfigurationException {
+ super(context, element);
+ check(element); // NOPMD. This invocation is normal.
+ }
+
+ /**
+ * Sets the flag enabling / disabling the factory classloader.
+ *
+ * @param use <code>true</code> enables the factory classloader.
+ */
+ public void setUseFactoryClassloader(boolean use) {
+ m_useFactoryClassloader = use;
+ }
+
+ /**
+ * Gets the component type description of the current factory.
+ *
+ * @return the description of the component type attached to this factory.
+ * @see org.apache.felix.ipojo.IPojoFactory#getComponentTypeDescription()
+ */
+ public ComponentTypeDescription getComponentTypeDescription() {
+ return new PrimitiveTypeDescription(this);
+ }
+
+ /**
+ * Allows a factory to check if the given element is well-formed.
+ * A component factory metadata is correct if they contain the 'classname' attribute.
+ * As this method is called from the (single-threaded) constructor, no synchronization is needed.
+ *
+ * @param element the metadata describing the component
+ * @throws ConfigurationException if the element describing the factory is malformed.
+ */
+ public void check(Element element) throws ConfigurationException {
+ m_classname = element.getAttribute("classname");
+ if (m_classname == null) {
+ throw new ConfigurationException("A component needs a class name : " + element);
+ }
+ m_manipulation = new PojoMetadata(m_componentMetadata);
+ }
+
+ /**
+ * Gets the class name.
+ * No synchronization needed, the classname is immutable.
+ *
+ * @return the class name.
+ * @see org.apache.felix.ipojo.IPojoFactory#getClassName()
+ */
+ public String getClassName() {
+ return m_classname;
+ }
+
+ /**
+ * Creates a primitive instance.
+ * This method is called when holding the lock.
+ *
+ * @param config the instance configuration
+ * @param context the service context (null if the instance has to be created in the global space).
+ * @param handlers the handlers to attach to the instance
+ * @return the created instance
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * if the configuration process failed.
+ * @see org.apache.felix.ipojo.IPojoFactory#createInstance(java.util.Dictionary, org.apache.felix.ipojo.IPojoContext, org.apache.felix.ipojo.HandlerManager[])
+ */
+ public ComponentInstance createInstance(Dictionary config, IPojoContext context, HandlerManager[] handlers) throws org.apache.felix.ipojo.ConfigurationException {
+ InstanceManager instance = new InstanceManager(this, context, handlers);
+
+ try {
+ instance.configure(m_componentMetadata, config);
+ instance.start();
+ return instance;
+ } catch (ConfigurationException e) {
+ // An exception occurs while executing the configure or start
+ // methods, the instance is stopped so the architecture service is still published and so we can debug
+ // the issue.
+ instance.stop();
+ throw e;
+ } catch (Throwable e) { // All others exception are handled here.
+ // As for the previous case, the instance is stopped.
+ instance.stop();
+ m_logger.log(Logger.INFO, "An error occurred when creating an instance of " + getFactoryName(), e);
+ throw new ConfigurationException(e.getMessage(), e);
+ }
+
+ }
+
+ /**
+ * Defines a class.
+ * This method needs to be synchronized to avoid that the classloader
+ * is created twice.
+ * This method delegates the <code>define</code> method invocation to the
+ * factory classloader.
+ *
+ * @param name the qualified name of the class
+ * @param clazz the byte array of the class
+ * @param domain the protection domain of the class
+ * @return the defined class object
+ */
+ public synchronized Class<? extends Object> defineClass(String name, byte[] clazz, ProtectionDomain domain) {
+ if (!m_useFactoryClassloader) {
+ m_logger.log(Log.WARNING, "A class definition was required even without the factory classloader enabled");
+ }
+
+ if (m_classLoader == null) {
+ m_classLoader = new FactoryClassloader(this);
+ }
+ return m_classLoader.defineClass(name, clazz, domain);
+ }
+
+ /**
+ * Loads a class. This method checks if the class
+ * to load is the implementation class or not.
+ * If it is, the factory classloader is used, else
+ * the {@link Bundle#loadClass(String)} is called.
+ *
+ * The implementation class is loaded using the factory classloader only if the factory classloader was enabled
+ *
+ * @param className the name of the class to load
+ * @return the resulting Class object
+ * @throws ClassNotFoundException if the class is not found
+ * @see #setUseFactoryClassloader(boolean)
+ */
+ public Class loadClass(String className) throws ClassNotFoundException {
+ if (m_useFactoryClassloader && m_clazz != null && m_classname.equals(className)) { // Immutable fields.
+ return defineClass(className, m_clazz, null);
+ }
+ return m_context.getBundle().loadClass(className);
+ }
+
+ /**
+ * Starts the factory.
+ * This method is not called when holding the monitor lock.
+ */
+ public void starting() {
+ if (m_tracker == null) {
+ if (m_requiredHandlers.size() != 0) {
+ try {
+ String filter = "(&(" + Handler.HANDLER_TYPE_PROPERTY + "=" + PrimitiveHandler.HANDLER_TYPE + ")" + "(factory.state=1)" + ")";
+ m_tracker = new Tracker(m_context, m_context.createFilter(filter), this);
+ m_tracker.open();
+ } catch (InvalidSyntaxException e) {
+ m_logger.log(Logger.ERROR, "A factory filter is not valid: " + e.getMessage()); //Holding the lock should not be an issue here.
+ stop();
+ }
+ }
+ }
+ // Else, the tracking has already started.
+ }
+
+ /**
+ * Stops all the instance managers.
+ * This method is called when holding the lock.
+ */
+ public void stopping() {
+ if (m_tracker != null) {
+ m_tracker.close();
+ m_tracker = null;
+ }
+ }
+
+ /**
+ * Computes the factory name. The factory name is computed from
+ * the 'name' and 'classname' attributes.
+ * This method does not manipulate any non-immutable fields,
+ * so does not need to be synchronized.
+ *
+ * @return the factory name.
+ */
+ public String getFactoryName() {
+ String name = m_componentMetadata.getAttribute("name");
+ if (name == null) {
+ // No factory name, use the classname (mandatory attribute)
+ name = m_componentMetadata.getAttribute("classname");
+ }
+ return name;
+ }
+
+ /**
+ * Computes required handlers.
+ * This method does not manipulate any non-immutable fields,
+ * so does not need to be synchronized.
+ * This method checks the {@link ComponentFactory#HANDLER_AUTO_PRIMITIVE}
+ * system property to add the listed handlers to the required handler set.
+ *
+ * @return the required handler list.
+ */
+ public List<RequiredHandler> getRequiredHandlerList() {
+ List<RequiredHandler> list = new ArrayList<RequiredHandler>();
+ Element[] elems = m_componentMetadata.getElements();
+ for (Element current : elems) {
+ if (!"manipulation".equals(current.getName())) { // Remove the manipulation element
+ RequiredHandler req = new RequiredHandler(current.getName(), current.getNameSpace());
+ if (!list.contains(req)) {
+ list.add(req);
+ }
+ }
+ }
+
+ // Add architecture if architecture != 'false'
+ String arch = m_componentMetadata.getAttribute("architecture");
+ if (arch == null || arch.equalsIgnoreCase("true")) {
+ list.add(new RequiredHandler("architecture", null));
+ }
+
+
+ // Determine if the component must be immediate.
+ // A component becomes immediate if it doesn't provide a service,
+ // and does not specified that the component is not immediate.
+ if (m_componentMetadata.getElements("provides") == null) {
+ String imm = m_componentMetadata.getAttribute("immediate");
+ if (imm == null) { // immediate not specified, set the immediate attribute to true
+ getLogger().log(
+ Logger.INFO,
+ "The component type " + getFactoryName()
+ + " becomes immediate");
+ m_componentMetadata.addAttribute(new Attribute("immediate",
+ "true"));
+ }
+ }
+
+ // Add lifecycle callback if immediate = true
+ RequiredHandler reqCallback = new RequiredHandler("callback", null);
+ String imm = m_componentMetadata.getAttribute("immediate");
+ if (!list.contains(reqCallback) && imm != null && imm.equalsIgnoreCase("true")) {
+ list.add(reqCallback);
+ }
+
+ // Manage auto attached handler.
+ String v = System.getProperty(HANDLER_AUTO_PRIMITIVE);
+ if (v != null && v.length() != 0) {
+ String[] hs = ParseUtils.split(v, ",");
+ for (String h1 : hs) {
+ String h = h1.trim();
+ String[] segments = ParseUtils.split(h, ":");
+ RequiredHandler rq = null;
+ if (segments.length == 2) { // External handler
+ rq = new RequiredHandler(segments[1], segments[0]);
+ } else if (segments.length == 1) { // Core handler
+ rq = new RequiredHandler(segments[1], null);
+ } // Others case are ignored.
+
+ if (rq != null) {
+ // Check it's not already contained
+ if (!list.contains(rq)) {
+ list.add(rq);
+ }
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * This method is called when a new handler factory is detected.
+ * Test if the factory can be used or not.
+ * This method need to be synchronized as it accesses to the content
+ * of required handlers.
+ *
+ * @param reference the new service reference.
+ * @return <code>true</code> if the given factory reference matches with a required handler.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+ */
+ public synchronized boolean addingService(ServiceReference reference) {
+ for (int i = 0; i < m_requiredHandlers.size(); i++) {
+ RequiredHandler req = (RequiredHandler) m_requiredHandlers.get(i);
+ if (req.getReference() == null && match(req, reference)) {
+ int oldP = req.getLevel();
+ req.setReference(reference);
+ // If the priority has changed, sort the list.
+ if (oldP != req.getLevel()) {
+ // Manipulate the list.
+ Collections.sort(m_requiredHandlers);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This method is called when a matching service has been added to the tracker,
+ * we can no compute the factory state. This method is synchronized to avoid
+ * concurrent calls to method modifying the factory state.
+ *
+ * @param reference the added service reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public synchronized void addedService(ServiceReference reference) {
+ if (m_state == INVALID) {
+ computeFactoryState();
+ }
+ }
+
+ /**
+ * This method is called when a used handler factory disappears.
+ * This method is synchronized to avoid concurrent calls to method modifying
+ * the factory state.
+ *
+ * @param reference the leaving service reference.
+ * @param service the handler factory object.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public synchronized void removedService(ServiceReference reference, Object service) {
+ // Look for the implied reference and invalid the handler identifier
+ for (Object m_requiredHandler : m_requiredHandlers) {
+ RequiredHandler req = (RequiredHandler) m_requiredHandler;
+ if (reference.equals(req.getReference())) {
+ req.unRef(); // This method will unget the service.
+ computeFactoryState();
+ return; // The factory can be used only once.
+ }
+ }
+ }
+
+ /**
+ * This method is called when a used handler factory is modified.
+ * However, handler factory modification is not possible, so this method
+ * is never called.
+ *
+ * @param reference the service reference
+ * @param service the Factory object (if already get)
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Noting to do
+ }
+
+ /**
+ * Returns manipulation metadata of this component type.
+ *
+ * @return manipulation metadata of this component type.
+ */
+ public PojoMetadata getPojoMetadata() {
+ return m_manipulation;
+ }
+
+ /**
+ * Gets the version of the component type.
+ *
+ * @return the version of <code>null</code> if not set.
+ * @see org.apache.felix.ipojo.Factory#getVersion()
+ */
+ public String getVersion() {
+ return m_version;
+ }
+
+ public ClassLoader getBundleClassLoader() {
+ return m_classLoader;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentInstance.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentInstance.java
new file mode 100644
index 0000000..4f2ca74
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentInstance.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This class defines the iPOJO's component instance concept.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ComponentInstance {
+
+ /**
+ * Component Instance State : DISPOSED. The component instance was disposed.
+ */
+ int DISPOSED = -1;
+
+ /**
+ * Component Instance State : STOPPED. The component instance is not
+ * started.
+ */
+ int STOPPED = 0;
+
+ /**
+ * Component Instance State : INVALID. The component instance is invalid when it
+ * starts or when a component dependency is invalid.
+ */
+ int INVALID = 1;
+
+ /**
+ * Component Instance State : VALID. The component instance is resolved when it is
+ * running and all its attached handlers are valid.
+ */
+ int VALID = 2;
+
+ /**
+ * Starts the component instance.
+ */
+ void start();
+
+ /**
+ * Stops the component instance.
+ * A stopped instance can be re-started.
+ */
+ void stop();
+
+ /**
+ * Disposes the component instance.
+ * A disposed instance cannot be re-started.
+ */
+ void dispose();
+
+ /**
+ * Returns the actual state of the instance.
+ * @return the actual state of the component instance.
+ */
+ int getState();
+
+ /**
+ * Returns the instance description.
+ * @return the instance description of the current instance
+ */
+ InstanceDescription getInstanceDescription();
+
+ /**
+ * Returns the factory who created this instance.
+ * @return the factory of the component instance.
+ */
+ ComponentFactory getFactory();
+
+ /**
+ * Returns the bundle context of this instance.
+ * @return the context of the component instance
+ */
+ BundleContext getContext();
+
+ /**
+ * Returns the name of the instance.
+ * @return the name of the component instance
+ */
+ String getInstanceName();
+
+ /**
+ * Checks if the instance is started.
+ * @return <code>true</code> if {@link ComponentInstance#getState()}
+ * returns {@link ComponentInstance#INVALID} or {@link ComponentInstance#VALID}.
+ */
+ boolean isStarted();
+
+ /**
+ * Re-configures an instance. Do nothing if the instance does not support
+ * dynamic reconfiguration. The reconfiguration does not stop the instance.
+ * @param configuration the new configuration.
+ */
+ void reconfigure(Dictionary configuration);
+
+ /**
+ * Adds an instance state listener on the current instance.
+ * @param listener the listener to add.
+ */
+ void addInstanceStateListener(InstanceStateListener listener);
+
+ /**
+ * Removes an instance state listener on the current instance.
+ * @param listener the listener to remove.
+ */
+ void removeInstanceStateListener(InstanceStateListener listener);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationException.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationException.java
new file mode 100644
index 0000000..4e34f74
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationException.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+/**
+ * This class defines the exception thrown when an instance cannot be configured correctly.
+ * This exception occurs when component metadata are not correct.
+ * @see Exception
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConfigurationException extends Exception {
+
+ /**
+ * Serialization Id.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The component type on which the error occurs.
+ * Uses the factory name.
+ */
+ private String m_type;
+
+ /**
+ * Creates a new configuration exception.
+ * @param message the error message
+ * @see Exception#Exception(String)
+ */
+ public ConfigurationException(String message) {
+ this(message, (String) null);
+ }
+
+ /**
+ * Creates a new configuration exception.
+ * @param mes the error message
+ * @param type the component type
+ * @see Exception#Exception(String)
+ */
+ public ConfigurationException(String mes, String type) {
+ this(mes, null, type);
+ }
+
+ public ConfigurationException(String message, Throwable cause) {
+ this(message, cause, null);
+ }
+
+ public ConfigurationException(String message, Throwable cause, String type) {
+ super(message, cause);
+ m_type = type;
+ }
+
+ /**
+ * Gets the error message.
+ * @return the error message.
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ if (m_type == null) {
+ return super.getMessage();
+ } else {
+ return "The configuration is not correct for the type " + m_type + " : " + super.getMessage();
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationTracker.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationTracker.java
new file mode 100644
index 0000000..04fd592
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConfigurationTracker.java
@@ -0,0 +1,327 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.extender.internal.Extender;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.ServiceLocator;
+import org.osgi.framework.*;
+import org.osgi.service.cm.*;
+import org.osgi.service.cm.ConfigurationException;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * An object tracking configuration from the configuration admin. It delegates to the underlying factories or
+ * component instance the action.
+ * <p/>
+ * This class implements a Configuration Listener, so events are received asynchronously.
+ */
+public class ConfigurationTracker implements ConfigurationListener {
+
+ /**
+ * The tracker instance.
+ */
+ private static ConfigurationTracker m_singleton;
+ private final ServiceRegistration m_registration;
+ private final BundleContext m_context;
+ private final Logger m_logger;
+ private Map<String, IPojoFactory> m_factories = new HashMap<String, IPojoFactory>();
+
+ public ConfigurationTracker() {
+ m_context = Extender.getIPOJOBundleContext();
+ m_logger = new Logger(m_context, "iPOJO Configuration Admin listener", Log.INFO);
+ // register as listener for configurations
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_DESCRIPTION, "iPOJO Configuration Admin Listener");
+ props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+ m_registration = m_context.registerService(ConfigurationListener.class.getName(), this, props);
+ }
+
+ public static void initialize() {
+ synchronized (ConfigurationTracker.class) {
+ if (m_singleton == null) {
+ m_singleton = new ConfigurationTracker();
+ }
+ }
+ }
+
+ public static void shutdown() {
+ m_singleton.dispose();
+ m_singleton = null;
+ }
+
+ public static ConfigurationTracker get() {
+ return m_singleton;
+ }
+
+ /**
+ * This method must be called by the iPOJO System itself, and only once.
+ */
+ public synchronized void dispose() {
+ if (m_registration != null) {
+ m_registration.unregister();
+ }
+ m_factories.clear();
+ }
+
+ public synchronized void registerFactory(IPojoFactory factory) {
+ m_factories.put(factory.getFactoryName(), factory);
+
+ ServiceLocator<ConfigurationAdmin> locator = new ServiceLocator<ConfigurationAdmin>(ConfigurationAdmin
+ .class, m_context);
+ final ConfigurationAdmin admin = locator.get();
+ if (admin == null) {
+ return;
+ }
+
+ List<Configuration> configurations = findFactoryConfiguration(admin, factory);
+ for (Configuration configuration : configurations) {
+ try {
+ factory.updated(configuration.getPid(), configuration.getProperties());
+ } catch (ConfigurationException e) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure instance " + configuration.getPid() + " from " +
+ configuration.getFactoryPid() + " with the configuration : " + configuration.getProperties(),
+ e);
+ }
+ }
+ }
+
+ public synchronized void instanceCreated(ComponentInstance instance) {
+ ServiceLocator<ConfigurationAdmin> locator = new ServiceLocator<ConfigurationAdmin>(ConfigurationAdmin
+ .class, m_context);
+ final ConfigurationAdmin admin = locator.get();
+ if (admin == null) {
+ return;
+ }
+
+ Configuration configuration = findSingletonConfiguration(admin, instance.getInstanceName());
+ if (configuration != null) {
+ Hashtable<String, Object> conf = copyConfiguration(configuration);
+ if (!conf.containsKey(Factory.INSTANCE_NAME_PROPERTY)) {
+ conf.put(Factory.INSTANCE_NAME_PROPERTY, configuration.getPid());
+ }
+ try {
+ instance.getFactory().reconfigure(conf);
+ } catch (UnacceptableConfiguration unacceptableConfiguration) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure the instance " + configuration.getPid() + " - the " +
+ "configuration is unacceptable", unacceptableConfiguration);
+ } catch (MissingHandlerException e) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure the instance " + configuration.getPid() + " - factory is " +
+ "invalid", e);
+ }
+ }
+ }
+
+ public synchronized void unregisterFactory(IPojoFactory factory) {
+ m_factories.remove(factory.getFactoryName());
+ }
+
+ public void configurationEvent(ConfigurationEvent event) {
+ String pid = event.getPid();
+ String factoryPid = event.getFactoryPid();
+
+ if (factoryPid == null) {
+ ComponentInstance instance = retrieveInstance(pid);
+ if (instance != null) {
+ manageConfigurationEventForSingleton(instance, event);
+ }
+ } else {
+ IPojoFactory factory = retrieveFactory(factoryPid);
+ if (factory != null) {
+ manageConfigurationEventForFactory(factory, event);
+ }
+ // Else the factory is unknown, do nothing.
+ }
+
+ }
+
+ private void manageConfigurationEventForFactory(final IPojoFactory factory, final ConfigurationEvent event) {
+ ServiceLocator<ConfigurationAdmin> locator = new ServiceLocator<ConfigurationAdmin>(ConfigurationAdmin
+ .class, m_context);
+
+ switch (event.getType()) {
+ case ConfigurationEvent.CM_DELETED:
+ factory.deleted(event.getPid());
+ break;
+ case ConfigurationEvent.CM_UPDATED:
+ final ConfigurationAdmin admin = locator.get();
+ if (admin == null) {
+ break;
+ }
+ final Configuration config = getConfiguration(admin, event.getPid(),
+ factory.getBundleContext().getBundle());
+ if (config != null) {
+ try {
+ factory.updated(event.getPid(), config.getProperties());
+ } catch (org.osgi.service.cm.ConfigurationException e) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure instance " + event.getPid() + " with the new " +
+ "configuration " + config.getProperties(), e);
+ }
+ }
+ default:
+ // To nothing.
+ }
+
+ locator.unget();
+ }
+
+ private void manageConfigurationEventForSingleton(final ComponentInstance instance,
+ final ConfigurationEvent event) {
+ ServiceLocator<ConfigurationAdmin> locator = new ServiceLocator<ConfigurationAdmin>(ConfigurationAdmin
+ .class, m_context);
+
+ switch (event.getType()) {
+ case ConfigurationEvent.CM_DELETED:
+ instance.dispose();
+ break;
+ case ConfigurationEvent.CM_UPDATED:
+ final ConfigurationAdmin admin = locator.get();
+ if (admin == null) {
+ break;
+ }
+ final Configuration config = getConfiguration(admin, event.getPid(),
+ instance.getFactory().getBundleContext().getBundle());
+ if (config != null) {
+ Hashtable<String, Object> conf = copyConfiguration(config);
+ if (!conf.containsKey(Factory.INSTANCE_NAME_PROPERTY)) {
+ conf.put(Factory.INSTANCE_NAME_PROPERTY, event.getPid());
+ }
+ try {
+ instance.getFactory().reconfigure(conf);
+ } catch (UnacceptableConfiguration unacceptableConfiguration) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure the instance " + event.getPid() + " - the " +
+ "configuration is unacceptable", unacceptableConfiguration);
+ } catch (MissingHandlerException e) {
+ m_logger.log(Log.ERROR, "Cannot reconfigure the instance " + event.getPid() + " - factory is " +
+ "invalid", e);
+ }
+ }
+ default:
+ // To nothing.
+ }
+
+ locator.unget();
+ }
+
+ private Hashtable<String, Object> copyConfiguration(Configuration config) {
+ Hashtable<String, Object> conf = new Hashtable<String, Object>();
+ // Copy configuration
+ Enumeration keys = config.getProperties().keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ conf.put(key, config.getProperties().get(key));
+ }
+ return conf;
+ }
+
+ private IPojoFactory retrieveFactory(String factoryPid) {
+ synchronized (this) {
+ return m_factories.get(factoryPid);
+ }
+ }
+
+ private ComponentInstance retrieveInstance(String instanceName) {
+ Collection<IPojoFactory> factories;
+ synchronized (this) {
+ factories = m_factories.values();
+ }
+ for (IPojoFactory factory : factories) {
+ ComponentInstance instance = factory.getInstanceByName(instanceName);
+ if (instance != null) {
+ return instance;
+ }
+ }
+ return null;
+ }
+
+ private Configuration getConfiguration(final ConfigurationAdmin admin, final String pid,
+ final Bundle bundle) {
+ if (admin == null) {
+ return null;
+ }
+
+ try {
+ // Even if it is possible, we don't build the filter with bundle.location to detect the case where the
+ // configuration exists but can't be managed by iPOJO.
+ final Configuration cfg = admin.getConfiguration(pid);
+ final String bundleLocation = bundle.getLocation();
+ if (cfg.getBundleLocation() == null || bundleLocation.equals(cfg.getBundleLocation())
+ || m_context.getBundle().getLocation().equals(cfg.getBundleLocation())) {
+ cfg.setBundleLocation(bundleLocation);
+ return cfg;
+ }
+
+ // Multi-location
+ if (cfg.getBundleLocation().startsWith("?")) {
+ if (bundle.hasPermission(new ConfigurationPermission(cfg.getBundleLocation(), "target"))) {
+ return cfg;
+ }
+ }
+
+ // configuration belongs to another bundle, cannot be used here
+ m_logger.log(Log.ERROR, "Cannot use configuration pid=" + pid + " for bundle "
+ + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation());
+ } catch (IOException ioe) {
+ m_logger.log(Log.WARNING, "Failed reading configuration for pid=" + pid, ioe);
+ }
+
+ return null;
+ }
+
+ public List<Configuration> findFactoryConfiguration(final ConfigurationAdmin admin, final IPojoFactory factory) {
+ final String filter = "(service.factoryPid=" + factory.getFactoryName() + ")";
+ return findConfigurations(admin, filter);
+ }
+
+ public Configuration findSingletonConfiguration(final ConfigurationAdmin admin, final String pid) {
+ final String filter = "(service.pid=" + pid + ")";
+ List<Configuration> list = findConfigurations(admin, filter);
+ if (list.isEmpty()) {
+ return null;
+ } else {
+ return list.get(0);
+ }
+ }
+
+ private List<Configuration> findConfigurations(final ConfigurationAdmin admin, final String filter) {
+ List<Configuration> configurations = Collections.emptyList();
+ if (admin == null) {
+ return configurations;
+ }
+
+ try {
+ Configuration[] list = admin.listConfigurations(filter);
+ if (list == null) {
+ return configurations;
+ } else {
+ return Arrays.asList(list);
+ }
+ } catch (InvalidSyntaxException e) {
+ m_logger.log(Log.ERROR, "Invalid Configuration selection filter " + filter, e);
+ } catch (IOException e) {
+ m_logger.log(Log.ERROR, "Error when retrieving configurations for filter=" + filter, e);
+ }
+ return configurations;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConstructorInjector.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConstructorInjector.java
new file mode 100644
index 0000000..0e27735
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ConstructorInjector.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * Interface implemented to support constructor parameter injection.
+ * When a new POJO object has to be created, all constructor injectors are
+ * called to gets the objects to injects as well as the type (to discover
+ * the constructor).
+ * Handlers willing to inject constructor parameters must register themselves
+ * using {@link InstanceManager#register(int, ConstructorInjector)} where
+ * the integer is the parameter index. Only one injector can inject a value
+ * for a specific index. If several injectors are registered for the same index,
+ * the component type is declared as invalid.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ConstructorInjector {
+
+ /**
+ * Gets the object to inject in the constructor parameter.
+ * @param index the parameter index
+ * @return the object to be injected.
+ */
+ Object getConstructorParameter(int index);
+
+ /**
+ * Gets the type of the object to inject in the constructor parameter.
+ * This is the type looked into the Pojo class, so it must match.
+ * Returning <code>null</code> will try to get the class from the
+ * injected object, however this can be wrong (implementation instead of interface,
+ * boxed objects...) and error-prone.
+ * @param index the parameter index
+ * @return the Class object (must fit also for primitive type)
+ */
+ Class getConstructorParameterType(int index);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextListener.java
new file mode 100644
index 0000000..a2d0fa0
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+
+/**
+ * Context Source Listener interface.
+ * A context source listener is notified when a monitored context
+ * property value changed.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ContextListener {
+
+ /**
+ * A monitored value has been modified.
+ * @param source the context source containing the property
+ * @param property the modified property name
+ * @param value the new value of the property
+ */
+ void update(ContextSource source, String property, Object value);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextSource.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextSource.java
new file mode 100644
index 0000000..de9a8eb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ContextSource.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+
+/**
+ * Context Source service interface.
+ * A context source advertises of context changes.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ContextSource {
+
+ /**
+ * Gets the current value of the given property.
+ * @param property property name
+ * @return the property value (<code>null</code> if unknown)
+ */
+ Object getProperty(String property);
+
+ /**
+ * Gets the entire context.
+ * @return the dictionary [Property, Value]
+ */
+ Dictionary getContext();
+
+ /**
+ * Registers a context listener on the given set of properties.
+ * The listener will be notified of every changes made on monitored properties.
+ * @param listener the context listener to register.
+ * @param properties property set monitored by the listener.
+ */
+ void registerContextListener(ContextListener listener, String[] properties);
+
+ /**
+ * Unregisters the given context listener.
+ * @param listener the listener to unregister.
+ */
+ void unregisterContextListener(ContextListener listener);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java
new file mode 100644
index 0000000..4792594
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ErrorHandler.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * Error Handler Service Definition.
+ * When exposed, this service is invoked when iPOJO throws a warning
+ * or an error. It's a hook on the internal iPOJO logger.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ErrorHandler {
+
+ /**
+ * Method invokes when an error occurred.
+ * @param instance the instance (can be <code>null</null>)
+ * @param message the error message
+ * @param error the error itself (can be <code>null</code>)
+ */
+ public void onError(ComponentInstance instance, String message, Throwable error);
+
+ /**
+ * Method invokes when a warning occurred.
+ * @param instance the instance (can be <code>null</null>)
+ * @param message the error message
+ * @param error the error itself (can be <code>null</code>)
+ */
+ public void onWarning(ComponentInstance instance, String message, Throwable error);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/EventDispatcher.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/EventDispatcher.java
new file mode 100644
index 0000000..0733d7b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/EventDispatcher.java
@@ -0,0 +1,181 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+
+/**
+ * iPOJO Internal event dispatcher.
+ * This class provides an internal service event dispatcher in order to tackle the
+ * event storm that can happen when starting large-scale applications.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see org.osgi.framework.ServiceListener
+ */
+public final class EventDispatcher implements ServiceListener {
+
+ /**
+ * The internal event dispatcher.
+ * This dispatcher is a singleton.
+ */
+ private static EventDispatcher DISPATCHER;
+
+ /**
+ * The list of listeners.
+ * Service interface -> List of {@link ServiceListener}
+ */
+ private Map m_listeners;
+ /**
+ * The global bundle context.
+ * This is the bundle context from iPOJO.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Creates the EventDispatcher.
+ * @param bc the bundle context used to register and unregister
+ * {@link ServiceListener}.
+ */
+ private EventDispatcher(BundleContext bc) {
+ m_context = bc;
+ m_listeners = new HashMap();
+ // Only one thread can call the start method.
+ m_context.addServiceListener(this);
+ }
+
+ /**
+ * Creates the internal event
+ * dispatcher.
+ * @param bc the iPOJO bundle context to send to the
+ * internal event dispatcher.
+ */
+ public static void create(BundleContext bc) {
+ DISPATCHER = new EventDispatcher(bc);
+ }
+
+ /**
+ * Stops and delete the internal event dispatcher.
+ * This method must be call only
+ * if iPOJO is stopping.
+ */
+ public static void dispose() {
+ DISPATCHER.stop();
+ DISPATCHER = null;
+ }
+
+
+ /**
+ * Gets the iPOJO event dispatcher.
+ * @return the event dispatcher or
+ * <code>null</code> if not created.
+ */
+ public static EventDispatcher getDispatcher() {
+ return DISPATCHER;
+ }
+
+
+ /**
+ * Stops the event dispatcher.
+ * This method unregisters the {@link ServiceListener}.
+ * This methods must be called only when the iPOJO bundle
+ * stops.
+ */
+ private void stop() {
+ synchronized (this) {
+ m_context.removeServiceListener(this);
+ m_listeners.clear();
+ }
+ }
+
+ /**
+ * Method called when a {@link ServiceEvent} is
+ * fired by the OSGi framework.
+ * According to the event, this method dispatches
+ * to interested registered listers from
+ * the {@link EventDispatcher#m_listeners} map.
+ * @param event the service event
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent event) {
+ String[] itfs = (String[]) event.getServiceReference().getProperty(Constants.OBJECTCLASS);
+ for (int s = 0; s < itfs.length; s++) {
+ List list;
+ synchronized (this) {
+ List stored = (List) m_listeners.get(itfs[s]);
+ if (stored == null) {
+ return; // Nothing to do
+ }
+ // Creates a new list (stack confinement)
+ list = new ArrayList(stored);
+ }
+ for (int i = 0; i < list.size(); i++) {
+ ((ServiceListener) list.get(i)).serviceChanged(event);
+ }
+ }
+ }
+
+ /**
+ * Adds a new service listener to the {@link EventDispatcher#m_listeners}
+ * map. This method specifies the listen service interface
+ * @param itf the service interface
+ * @param listener the service listener
+ */
+ public void addListener(String itf, ServiceListener listener) {
+ synchronized (this) {
+ List list = (List) m_listeners.get(itf);
+ if (list == null) {
+ list = new ArrayList(1);
+ list.add(listener);
+ m_listeners.put(itf, list);
+ } else {
+ list.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes a service listener.
+ * @param listener the service listener to remove
+ * @return <code>true</code> if the listener is
+ * successfully removed.
+ */
+ public boolean removeListener(ServiceListener listener) {
+ boolean removed = false;
+ synchronized (this) {
+ Set keys = m_listeners.keySet();
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ String itf = (String) it.next();
+ List list = (List) m_listeners.get(itf);
+ removed = removed || list.remove(listener);
+ }
+ }
+ return removed;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Factory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Factory.java
new file mode 100644
index 0000000..c4c6fe5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Factory.java
@@ -0,0 +1,205 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+import java.util.Dictionary;
+import java.util.List;
+
+/**
+ * Component Type Factory Service. This service is exposed by a instance manager factory, and allows the dynamic creation of component instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Factory {
+
+ /**
+ * Factory State.
+ * A valid factory is a factory where all required handlers are available.
+ */
+ int VALID = 1;
+ /**
+ * Factory State.
+ * An invalid factory is a factory where at least one required handler is
+ * unavailable. Creating an instance with an invalid factory failed.
+ */
+ int INVALID = 0;
+ /**
+ * Instance configuration can set the instance name using this property.
+ */
+ String INSTANCE_NAME_PROPERTY = "instance.name";
+ /**
+ * Instance configuration can set the factory version they target using this property.
+ */
+ String FACTORY_VERSION_PROPERTY = "factory.version";
+
+ /**
+ * Creates an instance manager (i.e. component type instance).
+ *
+ * @param configuration the configuration properties for this component.
+ * @return the created instance manager.
+ * @throws UnacceptableConfiguration if the given configuration is not valid.
+ * @throws MissingHandlerException if an handler is missing.
+ * @throws ConfigurationException if the instance configuration failed.
+ */
+ ComponentInstance createComponentInstance(Dictionary configuration) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException;
+
+ /**
+ * Creates an instance manager (i.e. component type instance).
+ * The instance is created in the scope given in argument.
+ *
+ * @param configuration the configuration properties for this component.
+ * @param serviceContext the service context of the component.
+ * @return the created instance manager.
+ * @throws UnacceptableConfiguration if the given configuration is not valid.
+ * @throws MissingHandlerException if an handler is missing.
+ * @throws ConfigurationException if the instance configuration failed.
+ */
+ ComponentInstance createComponentInstance(Dictionary configuration, ServiceContext serviceContext) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException;
+
+ /**
+ * Gets the component type information containing provided service,
+ * configuration properties ...
+ *
+ * @return the component type information.
+ */
+ Element getDescription();
+
+ /**
+ * Gets the component type description.
+ *
+ * @return the component type description object
+ */
+ ComponentTypeDescription getComponentDescription();
+
+ /**
+ * Checks if the given configuration is acceptable as a configuration
+ * of a component instance.
+ *
+ * @param conf the configuration to test
+ * @return <code>true</code> if the configuration is acceptable
+ */
+ boolean isAcceptable(Dictionary conf);
+
+ /**
+ * Returns the factory name.
+ *
+ * @return the name of the factory.
+ */
+ String getName();
+
+ /**
+ * Reconfigures an instance already created. This configuration needs to
+ * have the name property to identify the instance.
+ *
+ * @param conf the configuration to reconfigure the instance. The instance.name property must be set to identify
+ * the instance to reconfigure.
+ * @throws UnacceptableConfiguration if the given configuration is not consistent for the targeted instance.
+ * @throws MissingHandlerException if an handler is missing.
+ */
+ void reconfigure(Dictionary conf) throws UnacceptableConfiguration, MissingHandlerException;
+
+ /**
+ * Adds a factory state listener on the current factory.
+ *
+ * @param listener the listener to add
+ */
+ void addFactoryStateListener(FactoryStateListener listener);
+
+ /**
+ * Removes the given factory state listener from the listener list.
+ *
+ * @param listener the listener to remove
+ */
+ void removeFactoryStateListener(FactoryStateListener listener);
+
+ /**
+ * Gets the list of missing handlers.
+ * The handlers are given under the form namespace:name
+ *
+ * @return the list containing the name of missing handlers
+ */
+ List getMissingHandlers();
+
+ /**
+ * Get the list of required handlers.
+ * The handlers are given under the form namespace:name
+ *
+ * @return the list containing the name of required handlers
+ */
+ List getRequiredHandlers();
+
+ /**
+ * Returns the class name of the component type.
+ * For factories which does not contains a class, return "composite"
+ *
+ * @return the class name of the component type or "composite"
+ * @deprecated
+ */
+ String getClassName();
+
+ /**
+ * Returns the state of the factory.
+ *
+ * @return the state of the factory
+ */
+ int getState();
+
+ /**
+ * Gets the bundle context of the factory.
+ *
+ * @return the bundle context of the factory.
+ */
+ BundleContext getBundleContext();
+
+ /**
+ * Gets the version of the component type.
+ *
+ * @return the component type version or <code>null</code> if
+ * not specified.
+ */
+ String getVersion();
+
+ /**
+ * Gets the component type metadata (Element - Attribute structure)
+ *
+ * @return the root element of the component metadata. The result must <b>not</b> be modified.
+ */
+ Element getComponentMetadata();
+
+ /**
+ * Gets the list of instances created by the factory. The instances must be still alive.
+ *
+ * @return the list of created (and living) instances
+ * @since 1.11.0
+ */
+ List<ComponentInstance> getInstances();
+
+ /**
+ * Gets the list of the names of the instances created by the factory. The instances must be still alive.
+ *
+ * @return the list of the names of created (and living) instances
+ * @since 1.11.0
+ */
+ List<String> getInstancesNames();
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryClassloader.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryClassloader.java
new file mode 100644
index 0000000..eb1d5d7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryClassloader.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class defines the classloader attached to a factory.
+ * This class loader is used to load the implementation (e.g. manipulated)
+ * class.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see ClassLoader
+ */
+class FactoryClassloader extends ClassLoader {
+
+ /**
+ * The map of defined classes [Name, Class Object].
+ */
+ private final Map<String, Class<?>> m_definedClasses = new HashMap<String, Class<?>>();
+ private ComponentFactory factory;
+
+ public FactoryClassloader(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * The defineClass method.
+ *
+ * @param name name of the class
+ * @param clazz the byte array of the class
+ * @param domain the protection domain
+ * @return the defined class.
+ */
+ public Class<?> defineClass(String name, byte[] clazz, ProtectionDomain domain) {
+ if (m_definedClasses.containsKey(name)) {
+ return m_definedClasses.get(name);
+ }
+ Class clas = super.defineClass(name, clazz, 0, clazz.length, domain);
+ m_definedClasses.put(name, clas);
+ return clas;
+ }
+
+ /**
+ * Returns the URL of the required resource.
+ *
+ * @param arg the name of the resource to find.
+ * @return the URL of the resource.
+ * @see ClassLoader#getResource(String)
+ */
+ public URL getResource(String arg) {
+ return factory.m_context.getBundle().getResource(arg);
+ }
+
+ /**
+ * Loads the given class.
+ *
+ * @param name the name of the class
+ * @param resolve should be the class resolve now ?
+ * @return the loaded class object
+ * @throws ClassNotFoundException if the class to load is not found
+ * @see ClassLoader#loadClass(String, boolean)
+ * @see ClassLoader#loadClass(String, boolean)
+ */
+ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ return factory.m_context.getBundle().loadClass(name);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryStateListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryStateListener.java
new file mode 100644
index 0000000..3d9dadd
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FactoryStateListener.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * A factory state listener received notification about monitored factory state changes.
+ * This listener allows anyone to be notified when the listened factory state changes.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface FactoryStateListener {
+
+ /**
+ * Notification listener.
+ * Each time an instance state changes, this method is called
+ * with the new factory state.
+ * @param factory the changing factory
+ * @param newState the new factory state
+ */
+ void stateChanged(Factory factory, int newState);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FieldInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FieldInterceptor.java
new file mode 100644
index 0000000..22e308d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/FieldInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+/**
+* A field interceptor is notified when a monitored field asks for a value or
+* receives a new value. A class implementing this interface is able to be
+* notified of field accesses, and is able to inject a value to this field.
+* The listener needs to be register on the instance manager.
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+public interface FieldInterceptor {
+
+ /**
+ * This method is called when a PUTFIELD operation is detected,
+ * e.g. an assignation.
+ * @param pojo the pojo object setting the value
+ * @param fieldName the field name
+ * @param value the value passed to the field
+ */
+ void onSet(Object pojo, String fieldName, Object value);
+
+ /**
+ * This method is called when a GETFIELD operation is detected.
+ * This method allows to inject a value to the field.
+ * @param pojo the pojo object getting the value
+ * @param fieldName the field name
+ * @param value the value passed to the field (by the previous call)
+ * @return the managed value of the field
+ */
+ Object onGet(Object pojo, String fieldName, Object value);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Handler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Handler.java
new file mode 100644
index 0000000..9e14cd5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Handler.java
@@ -0,0 +1,264 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+
+/**
+ * Handler Abstract Class.
+ * A handler is a 'piece' of
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class Handler {
+
+ /**
+ * The handler namespace property.
+ */
+ public static final String HANDLER_NAMESPACE_PROPERTY = "handler.namespace";
+
+ /**
+ * The handler name property.
+ */
+ public static final String HANDLER_NAME_PROPERTY = "handler.name";
+
+ /**
+ * The handler type property.
+ */
+ public static final String HANDLER_TYPE_PROPERTY = "handler.type";
+
+ /**
+ * The handler priority.
+ */
+ public static final String HANDLER_LEVEL_PROPERTY = "handler.level";
+
+ /**
+ * The current handler validity.
+ * This impacts directly the instance state.
+ */
+ protected boolean m_isValid = true;
+
+ /**
+ * The HandlerManager managing the current handler.
+ */
+ protected HandlerManager m_instance;
+
+ /**
+ * Sets the factory attached to this handler object.
+ * This method must be override to depend on each component factory type.
+ * @param factory the factory to attach.
+ */
+ public abstract void setFactory(Factory factory);
+
+ /**
+ * Gets the logger to use in the handler.
+ * This method must be override to depend on each component factory type logging policy.
+ * @return the logger.
+ */
+ public abstract Logger getLogger();
+
+ /**
+ * Log method (warning).
+ * Log a warning message to the handler logger.
+ * @param message the message to log
+ */
+ public final void warn(String message) {
+ getLogger().log(Logger.WARNING, message);
+ }
+
+ /**
+ * Log method (error).
+ * Log an error message to the handler logger.
+ * @param message the message to log
+ */
+ public final void error(String message) {
+ getLogger().log(Logger.ERROR, message);
+ }
+
+ /**
+ * Log method (info).
+ * Log an info message to the handler logger.
+ * @param message the message to log
+ */
+ public final void info(String message) {
+ getLogger().log(Logger.INFO, message);
+ }
+
+ /**
+ * Log method (debug).
+ * Log a debug message to the handler logger.
+ * @param message the message to log
+ */
+ public final void debug(String message) {
+ getLogger().log(Logger.DEBUG, message);
+ }
+
+ /**
+ * Log method (warning).
+ * Log a warning message to the handler logger.
+ * The message is sent with an attached exception.
+ * @param message the message to log
+ * @param exception the exception to attach with the message
+ */
+ public final void warn(String message, Throwable exception) {
+ getLogger().log(Logger.WARNING, message, exception);
+ }
+
+ /**
+ * Log method (error).
+ * Log an error message to the handler logger.
+ * The message is sent with an attached exception.
+ * @param message the message to log
+ * @param exception the exception to attach to the message
+ */
+ public final void error(String message, Throwable exception) {
+ getLogger().log(Logger.ERROR, message, exception);
+ }
+
+ /**
+ * Get a plugged handler of the same container.
+ * This method must be call only in the start method (or after).
+ * In the configure method, this method can not return a consistent
+ * result as all handlers are not plugged.
+ * @param name : name of the handler to find (class name or qualified handler name (ns:name)).
+ * @return the handler object or null if the handler is not found.
+ */
+ public abstract Handler getHandler(String name);
+
+ /**
+ * Attaches the current handler object to the given component instance.
+ * An attached handler becomes a part of the instance container.
+ * @param instance the component instance on which the current handler will be attached.
+ */
+ protected abstract void attach(ComponentInstance instance);
+
+ /**
+ * Checks if the current handler is valid.
+ * This check tests the handler validity.
+ * This method must not be override.
+ * @return <code>true</code> if the handler is valid.
+ */
+ public final boolean isValid() {
+ return ((Pojo) this).getComponentInstance().getState() == ComponentInstance.VALID;
+ }
+
+ /**
+ * Sets the validity of the current handler.
+ * @param isValid if <code>true</code> the handler becomes valid, else it becomes invalid.
+ */
+ public final void setValidity(boolean isValid) {
+ if (m_isValid != isValid) {
+ m_isValid = isValid;
+ HandlerManager instance = getHandlerManager();
+ if (isValid) {
+ instance.stateChanged(instance, ComponentInstance.VALID);
+ } else {
+ instance.stateChanged(instance, ComponentInstance.INVALID);
+ }
+ }
+ }
+
+ /**
+ * Is the current handler valid.
+ * @return <code>true</code> if the handler is valid, <code>false</code> otherwise.
+ */
+ public final boolean getValidity() {
+ return m_isValid;
+ }
+
+ /**
+ * Gets the component instance of the current handler.
+ * @return the component instance.
+ */
+ public final HandlerManager getHandlerManager() {
+ if (m_instance != null) { return m_instance; }
+ m_instance = (HandlerManager) ((Pojo) this).getComponentInstance();
+ return m_instance;
+ }
+
+ /**
+ * Initializes the component factory.
+ * This method aims to collect component factory properties.
+ * Each handler wanting to contribute needs to override this
+ * method and adds properties to the given component description.
+ * By default, this method does nothing.
+ * @param typeDesc the component description.
+ * @param metadata the component type metadata.
+ * @throws ConfigurationException if the metadata are not correct (early detection).
+ */
+ public void initializeComponentFactory(ComponentTypeDescription typeDesc, Element metadata) throws ConfigurationException {
+ // The default implementation does nothing.
+ }
+
+ /**
+ * Configures the handler.
+ * @param metadata the metadata of the component
+ * @param configuration the instance configuration
+ * @throws ConfigurationException if the metadata are not correct.
+ */
+ public abstract void configure(Element metadata, Dictionary configuration) throws ConfigurationException;
+
+ /**
+ * Stops the handler
+ * This method stops the management.
+ */
+ public abstract void stop();
+
+ /**
+ * Starts the handler
+ * This method starts the management.
+ */
+ public abstract void start();
+
+ /**
+ * This method is called when the component state changed.
+ * By default, this method does nothing.
+ * @param state the new instance state {@link ComponentInstance}
+ */
+ public void stateChanged(int state) {
+ // The default implementation does nothing.
+ }
+
+ /**
+ * Returns the current handler description.
+ * The simplest description contains only the name and the validity of the handler.
+ * If the handler override this method, it can customize the description.
+ * By default, this method returns the simplest description.
+ * @return the description of the handler.
+ */
+ public HandlerDescription getDescription() {
+ return new HandlerDescription(this);
+ }
+
+ /**
+ * Reconfigures the instance.
+ * This method is called, when the instance is under reconfiguration.
+ * The reconfiguration does not stops the instance, and so the handler supporting
+ * the reconfiguration must override this method and handles this case.
+ * By default, this method does nothing.
+ * @param configuration the new instance configuration.
+ */
+ public void reconfigure(Dictionary configuration) {
+ // The default implementation does nothing.
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerFactory.java
new file mode 100644
index 0000000..c4a969c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerFactory.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+
+/**
+ * Service interface published by handler factory.
+ * This interface allows interacting the the handler factory to create
+ * {@link Handler} objects.
+ * @see Factory
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface HandlerFactory extends Factory {
+
+ /**
+ * The iPOJO Default Namespace.
+ */
+ String IPOJO_NAMESPACE = "org.apache.felix.ipojo";
+
+ /**
+ * Gets the namespace associated with this handler factory.
+ * @return the namespace used by this handler
+ */
+ String getNamespace();
+
+ /**
+ * Gets the name associated with this handler factory.
+ * @return the name used by this handler
+ */
+ String getHandlerName();
+
+ /**
+ * Gets the type of the handler factory.
+ * The handler can only be plugged on instance container with the same type.
+ * Basically, types are <code>primitive</code> and <code>composite</code>.
+ * @return the type of the handler
+ */
+ String getType();
+
+ /**
+ * Gets the start level of the handler objects created by this factory.
+ * Handlers with a low start level are configured and started before
+ * handlers with an higher start level. Moreover, these handlers are
+ * stopped and disposed after.
+ * @return the handler's start level
+ */
+ int getStartLevel();
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManager.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManager.java
new file mode 100644
index 0000000..4472200
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManager.java
@@ -0,0 +1,244 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The handler manager manages an handler instance.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerManager extends InstanceManager {
+
+ /**
+ * The internal handler object.
+ * Immutable once set.
+ */
+ private Handler m_handler;
+
+ /**
+ * Creates a handler manager.
+ * @param factory the handler factory
+ * @param context the bundle context
+ * @param handlers the handler array
+ */
+ public HandlerManager(ComponentFactory factory, BundleContext context, HandlerManager[] handlers) {
+ super(factory, context, handlers);
+ }
+
+ /**
+ * Gets the contained handler object.
+ * If not already created it creates the object.
+ * @return the handler object.
+ */
+ public Handler getHandler() {
+ if (m_handler == null) {
+ createHandlerObject();
+ }
+ return m_handler;
+ }
+
+ /**
+ * Creates and initializes the handler object.
+ * @param instance the component instance on which the handler will be attached.
+ * @param metadata the component metadata.
+ * @param configuration the instance configuration.
+ * @throws ConfigurationException if the handler configuration failed.
+ */
+ public void init(ComponentInstance instance, Element metadata, Dictionary configuration) throws ConfigurationException {
+ createHandlerObject();
+ m_handler.setFactory(instance.getFactory());
+ m_handler.attach(instance);
+ m_handler.configure(metadata, configuration);
+ }
+
+ /**
+ * Creates the handler object.
+ * This method does nothing if the object is already created.
+ * This method does not need locking protocol as only one thread (the creator thread) can create an instance.
+ */
+ private void createHandlerObject() {
+ if (m_handler != null) { return; }
+ m_handler = (Handler) createPojoObject();
+ }
+
+ /**
+ * Creates an instance of the content.
+ * This method needs to be called once only for singleton provided service.
+ * This methods call the {@link InstanceManager#createObject()} method, and adds
+ * the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
+ * it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
+ * handlers.
+ * @return a new instance or <code>null</code> if an error occurs during the
+ * creation.
+ */
+ public Object createPojoObject() {
+ Object instance = createObject();
+
+ // Add the new instance in the instance list.
+ synchronized (this) {
+ if (m_pojoObjects == null) {
+ m_pojoObjects = new ArrayList(1);
+ }
+ m_pojoObjects.add(instance);
+ }
+
+ //Do not call onCreation, this will be done in the start method.
+
+ return instance;
+ }
+
+ /**
+ * Starts the instance manager.
+ */
+ public void start() {
+ synchronized (this) {
+ if (m_state != STOPPED) {
+ return; // Instance already started
+ } else {
+ m_state = -2; // Temporary starting state, avoiding concurrent starts.
+ }
+ }
+
+ // Start attached handler.
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].addInstanceStateListener(this);
+ m_handlers[i].start();
+ }
+
+ // Call the onCreation method.
+ for (int i = 0; i < m_handlers.length; i++) {
+ ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(m_handler);
+ }
+
+
+ m_handler.start(); // Call the handler start method, the instance might be invalid.
+
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (!m_handlers[i].getHandler().isValid()) {
+ setState(INVALID);
+ return;
+ }
+ }
+ if (m_handler.getValidity()) {
+ setState(VALID);
+ } else {
+ setState(INVALID);
+ }
+
+ // Now, the state is necessary different from the temporary state.
+ }
+
+ /**
+ * Stops the instance manager.
+ */
+ public void stop() {
+ synchronized (this) {
+ if (m_state == STOPPED) {
+ return; // Instance already stopped
+ } else {
+ m_state = -2; // Temporary state avoiding concurrent stopping.
+ }
+ }
+
+ setState(INVALID);
+
+ if (m_handler != null) {
+ m_handler.stop();
+ }
+
+ // Stop all the handlers
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].removeInstanceStateListener(this);
+ m_handlers[i].stop();
+ }
+
+ List listeners = null;
+ synchronized (this) {
+ m_state = STOPPED;
+ if (m_listeners != null) {
+ listeners = new ArrayList(m_listeners); // Stack confinement.
+ }
+ }
+
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ ((InstanceStateListener) listeners.get(i)).stateChanged(this, STOPPED);
+ }
+ }
+ }
+
+ /**
+ * Disposes the instance.
+ * @see org.apache.felix.ipojo.ComponentInstance#dispose()
+ */
+ public void dispose() {
+ super.dispose();
+ m_handler = null;
+ }
+
+ /**
+ * Kills the current instance.
+ * Only the factory of this instance can call this method.
+ */
+ protected void kill() {
+ super.dispose();
+ m_handler = null;
+ }
+
+ /**
+ * State Change listener callback.
+ * This method is notified at each time a plugged handler becomes invalid.
+ * @param instance the changing instance
+ * @param newState the new state
+ * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
+ */
+ public void stateChanged(ComponentInstance instance, int newState) {
+ int state;
+ synchronized (this) {
+ if (m_state <= STOPPED) {
+ return;
+ } else {
+ state = m_state; // Stack confinement
+ }
+ }
+ // Update the component state if necessary
+ if (newState == INVALID && state == VALID) {
+ // Need to update the state to UNRESOLVED
+ setState(INVALID);
+ return;
+ }
+ if (newState == VALID && state == INVALID) {
+ // An handler becomes valid => check if all handlers are valid
+ if (!m_handler.getValidity()) { return; }
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getState() != VALID) { return; }
+ }
+ setState(VALID);
+ return;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManagerFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManagerFactory.java
new file mode 100644
index 0000000..5e83935
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/HandlerManagerFactory.java
@@ -0,0 +1,223 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Implementation of the handler factory interface.
+ * This factory is able to create handler manager.
+ * A handler manager is an iPOJO instance containing a handler object.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerManagerFactory extends ComponentFactory implements HandlerFactory {
+
+ /**
+ * The Handler type (<code>composite</code> or <code>primitive</code>).
+ */
+ private final String m_type;
+
+ /**
+ * The iPOJO Handler Namespace.
+ * (Uses the iPOJO default namespace is not specified)
+ */
+ private final String m_namespace;
+
+ /**
+ * The handler start level.
+ * Lower levels are priority and so are configured and started
+ * before higher levels, and are stopped after.
+ */
+ private final int m_level;
+
+ /**
+ * Creates a handler factory.
+ * @param context the bundle context
+ * @param metadata the metadata of the component to create
+ * @throws ConfigurationException if the element describing the factory is malformed.
+ */
+ public HandlerManagerFactory(BundleContext context, Element metadata) throws ConfigurationException {
+ super(context, metadata);
+
+ // Get the name
+ m_factoryName = metadata.getAttribute("name");
+ if (m_factoryName == null) { throw new ConfigurationException("A Handler needs a name"); }
+
+ // Get the type
+ String type = metadata.getAttribute("type");
+ if (type != null) {
+ m_type = type;
+ } else {
+ m_type = "primitive"; // Set to primitive if not specified.
+ }
+
+ String level = metadata.getAttribute("level");
+ if (level != null) {
+ m_level = new Integer(level).intValue();
+ } else {
+ m_level = Integer.MAX_VALUE; // Set to max if not specified.
+ }
+
+ // Get the namespace
+ String namespace = metadata.getAttribute("namespace");
+ if (namespace != null) {
+ m_namespace = namespace.toLowerCase();
+ } else {
+ m_namespace = IPOJO_NAMESPACE; // Set to the iPOJO default namespace if not specified.
+ }
+ }
+
+ public String getNamespace() {
+ return m_namespace;
+ }
+
+ public String getHandlerName() {
+ return m_namespace + ":" + getName();
+ }
+
+ public String getType() {
+ return m_type;
+ }
+
+ public int getStartLevel() {
+ return m_level;
+ }
+
+ public ComponentTypeDescription getComponentTypeDescription() {
+ return new HandlerTypeDescription(this);
+ }
+
+ public String getFactoryName() {
+ if ("composite".equals(m_type) && IPOJO_NAMESPACE.equals(m_namespace)) {
+ // Artificially change the factory name, to avoid name clash when we generate the instance name.
+ return m_namespace + ".composite:" + getName();
+ }
+ return getHandlerName();
+ }
+
+ /**
+ * Stops the factory.
+ * This method does not disposed created instances.
+ * These instances will be disposed by the instance managers.
+ * This method is called with the lock.
+ */
+ public void stopping() {
+ if (m_tracker != null) {
+ m_tracker.close();
+ m_tracker = null;
+ }
+ }
+
+ /**
+ * Creates an instance. The given configuration needs to contain the 'name'
+ * property. This method is called when holding the lock.
+ * @param configuration the configuration of the created instance.
+ * @param context the service context to push for this instance.
+ * @param handlers the handler array to attach to the instance.
+ * @return the created {@link HandlerManager}.
+ * @throws org.apache.felix.ipojo.ConfigurationException if the instance configuration failed.
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
+ */
+ public ComponentInstance createInstance(Dictionary configuration, IPojoContext context, HandlerManager[] handlers) throws ConfigurationException {
+ HandlerManager instance = new HandlerManager(this, context, handlers);
+ instance.configure(m_componentMetadata, configuration);
+ return instance;
+ }
+
+
+ /**
+ * Computes required handlers. This method does not manipulate any
+ * non-immutable fields, so does not need to be synchronized.
+ * This method is overridden to avoid using the same detection rules
+ * than 'primitive' components. Indeed, architecture is disable by default,
+ * and a handler is never immediate.
+ * @return the required handler list.
+ */
+ public List<RequiredHandler> getRequiredHandlerList() {
+ List<RequiredHandler> list = new ArrayList<RequiredHandler>();
+ Element[] elems = m_componentMetadata.getElements();
+ for (int i = 0; i < elems.length; i++) {
+ Element current = elems[i];
+ if (!"manipulation".equals(current.getName())) { // Remove the manipulation element
+ RequiredHandler req = new RequiredHandler(current.getName(),
+ current.getNameSpace());
+ if (!list.contains(req)) {
+ list.add(req);
+ }
+ }
+ }
+
+ // Unlike normal components, the architecture is enable only when
+ // specified.
+ String arch = m_componentMetadata.getAttribute("architecture");
+ if (arch != null && arch.equalsIgnoreCase("true")) {
+ list.add(new RequiredHandler("architecture", null));
+ }
+
+ // The auto-attached handler list is ignored for handlers to avoid loops.
+
+ return list;
+ }
+
+ /**
+ * Defines the handler type description.
+ * @see ComponentTypeDescription
+ */
+ private class HandlerTypeDescription extends ComponentTypeDescription {
+
+ /**
+ * Creates the HandlerTypeDescription.
+ * @param factory the factory.
+ */
+ public HandlerTypeDescription(IPojoFactory factory) {
+ super(factory);
+ }
+
+ /**
+ * Add properties to publish.
+ * <li>handler.name</li>
+ * <li>handler.namespace</li>
+ * <li>handler.type</li>
+ * <li>handler.level if the level is not Integer.MAX</li>
+ * @return returns the dictionary to publish.
+ * @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish()
+ */
+ public Dictionary getPropertiesToPublish() {
+ Dictionary props = super.getPropertiesToPublish();
+
+ props.put(Handler.HANDLER_NAME_PROPERTY, m_factoryName);
+ props.put(Handler.HANDLER_NAMESPACE_PROPERTY, m_namespace);
+ props.put(Handler.HANDLER_TYPE_PROPERTY, m_type);
+ if (m_level != Integer.MAX_VALUE) {
+ props.put(Handler.HANDLER_LEVEL_PROPERTY, new Integer(m_level));
+ }
+ return props;
+ }
+
+ public String[] getFactoryInterfacesToPublish() {
+ return new String[] {HandlerFactory.class.getName()};
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java
new file mode 100644
index 0000000..a74f22d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+
+/**
+ * iPOJO Service Factory is a special service factory handling to get the
+ * instance consuming the service. The mechanism is equivalent to the OSGi Service
+ * Factory.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface IPOJOServiceFactory {
+
+ /**
+ * Gets a service object.
+ * @param instance the instance asking the for the service object.
+ * @return the service object.
+ */
+ Object getService(ComponentInstance instance);
+
+ /**
+ * Un-gets a service object.
+ * @param instance the instance un-getting the service object.
+ * @param svcObject the service object used
+ */
+ void ungetService(ComponentInstance instance, Object svcObject);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoContext.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoContext.java
new file mode 100644
index 0000000..165edc6
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoContext.java
@@ -0,0 +1,511 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * The iPOJO Context is a BundleContext implementation allowing the separation
+ * between Bundle context and Service (Bundle) Context.
+ * This is used inside composition to differentiate the classloading context (i.e.
+ * Bundle) and the service registry access.
+ * This class delegates calls to the good internal context (either the BundleContext
+ * or the ServiceContext) according to the method. If the instance does not have a valid
+ * service context, the bundle context is always used.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IPojoContext implements BundleContext, ServiceContext {
+
+ /**
+ * The bundleContext used to access bundle methods.
+ */
+ private BundleContext m_bundleContext;
+
+ /**
+ * The service context used to access to the service registry.
+ */
+ private ServiceContext m_serviceContext;
+
+ /**
+ * Creates an iPOJO Context.
+ * No service context is specified.
+ * This constructor is used when the
+ * instance lives in the global context.
+ * @param context the bundle context
+ */
+ public IPojoContext(BundleContext context) {
+ if (context instanceof IPojoContext) {
+ m_bundleContext = ((IPojoContext) context).getGlobalContext();
+ m_serviceContext = ((IPojoContext) context).getServiceContext();
+ } else {
+ m_bundleContext = context;
+ }
+ }
+
+ /**
+ * Creates an iPOJO Context.
+ * A service context is used to refer to the
+ * service registry. The service context will be
+ * used for all service accesses.
+ * @param bundleContext the bundle context
+ * @param serviceContext the service context
+ */
+ public IPojoContext(BundleContext bundleContext, ServiceContext serviceContext) {
+ m_bundleContext = bundleContext;
+ m_serviceContext = serviceContext;
+ }
+
+ /**
+ * Adds a bundle listener.
+ * @param listener the listener to add
+ * @see org.osgi.framework.BundleContext#addBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void addBundleListener(BundleListener listener) {
+ m_bundleContext.addBundleListener(listener);
+ }
+
+ /**
+ * Adds a framework listener.
+ * @param listener the listener object to add
+ * @see org.osgi.framework.BundleContext#addFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void addFrameworkListener(FrameworkListener listener) {
+ m_bundleContext.addFrameworkListener(listener);
+ }
+
+ /**
+ * Adds a service listener.
+ * This methods registers the listener on the service context
+ * if it specified. Otherwise, if the internal dispatcher is enabled,
+ * it registers the listener inside the internal dispatcher (if
+ * the filter match against the iPOJO Filter format
+ * {@link IPojoContext#match(String)}). Finally, if the internal
+ * dispatcher is disabled, it uses the "regular" bundle context.
+ * @param listener the service listener to add.
+ * @param filter the LDAP filter
+ * @throws InvalidSyntaxException if LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String)
+ */
+ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException {
+ if (m_serviceContext == null) {
+ EventDispatcher dispatcher = EventDispatcher.getDispatcher();
+ if (dispatcher != null) { // getDispatcher returns null if not enable.
+ String itf = match(filter);
+ if (itf != null) {
+ dispatcher.addListener(itf, listener);
+ } else {
+ m_bundleContext.addServiceListener(listener, filter);
+ }
+ } else {
+ m_bundleContext.addServiceListener(listener, filter);
+ }
+ } else {
+ m_serviceContext.addServiceListener(listener, filter);
+ }
+ }
+
+ /**
+ * Add a service listener.
+ * This methods registers the listener on the service context
+ * if it specified. Otherwise, it uses the "regular" bundle context.
+ * @param listener the service listener to add.
+ * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void addServiceListener(ServiceListener listener) {
+ if (m_serviceContext == null) {
+ m_bundleContext.addServiceListener(listener);
+ } else {
+ m_serviceContext.addServiceListener(listener);
+ }
+ }
+
+ /**
+ * This method checks if the filter matches with the iPOJO
+ * filter format: <code>(OBJECTCLASS=$ITF)</code>. It tries
+ * to extract the required interface (<code>$ITF</code>).
+ * @param filter the filter to analyze
+ * @return the required interface or <code>null</code>
+ * if the filter doesn't match with the iPOJO format.
+ */
+ private String match(String filter) {
+ if (filter != null && filter.startsWith("(" + Constants.OBJECTCLASS + "=") // check the beginning (OBJECTCLASS
+ && filter.lastIndexOf(')') == filter.indexOf(')')) { // check that there is only one )
+ return filter.substring(("(" + Constants.OBJECTCLASS + "=").length(), filter.length() - 1);
+ }
+ return null;
+ }
+
+
+
+ /**
+ * Creates a filter objects.
+ * This method always uses the bundle context.
+ * @param filter the string form of the LDAP filter to create
+ * @return the filter object.
+ * @throws InvalidSyntaxException if the given filter is malformed
+ * @see org.osgi.framework.BundleContext#createFilter(java.lang.String)
+ */
+ public Filter createFilter(String filter) throws InvalidSyntaxException {
+ return m_bundleContext.createFilter(filter);
+ }
+
+ /**
+ * Gets a bundle by symbolic name
+ * @param s the name
+ * @return the matching bundle or <code>null</code> if not found
+ */
+ public Bundle getBundle(String s) {
+ return m_bundleContext.getBundle(s);
+ }
+
+ /**
+ * Gets the service references matching with the given query.
+ * Uses the service context if specified, used the bundle context
+ * otherwise.
+ * @param clazz the required interface
+ * @param filter the LDAP filter
+ * @return the array of available service references
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#getAllServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ if (m_serviceContext == null) {
+ return m_bundleContext.getAllServiceReferences(clazz, filter);
+ } else {
+ return m_serviceContext.getAllServiceReferences(clazz, filter);
+ }
+ }
+
+ /**
+ * Gets the current bundle object.
+ * @return the bundle declaring the component type of the instance
+ * using the current IPojoContext.
+ * @see org.osgi.framework.BundleContext#getBundle()
+ */
+ public Bundle getBundle() {
+ return m_bundleContext.getBundle();
+ }
+
+ /**
+ * Gets the bundle object with the given id.
+ * @param bundleId the bundle id
+ * @return the bundle object
+ * @see org.osgi.framework.BundleContext#getBundle(long)
+ */
+ public Bundle getBundle(long bundleId) {
+ return m_bundleContext.getBundle(bundleId);
+ }
+
+ /**
+ * Gets installed bundles.
+ * @return the list of installed bundles
+ * @see org.osgi.framework.BundleContext#getBundles()
+ */
+ public Bundle[] getBundles() {
+ return m_bundleContext.getBundles();
+ }
+
+ /**
+ * Gets a data file.
+ * @param filename the file name.
+ * @return the File object
+ * @see org.osgi.framework.BundleContext#getDataFile(java.lang.String)
+ */
+ public File getDataFile(String filename) {
+ return m_bundleContext.getDataFile(filename);
+ }
+
+ /**
+ * Gets a property value.
+ * @param key the key of the asked property
+ * @return the property value (object) or <code>null</code> if no
+ * property are associated with the given key
+ * @see org.osgi.framework.BundleContext#getProperty(java.lang.String)
+ */
+ public String getProperty(String key) {
+ return m_bundleContext.getProperty(key);
+ }
+
+ /**
+ * Gets a service object.
+ * The given service reference must come from the same context than
+ * where the service is get.
+ * This method uses the service context if specified, the bundle
+ * context otherwise.
+ * This method may throw {@link IllegalStateException} if the used bundle
+ * context is no more valid (because we're leaving).
+ * @param ref the required service reference
+ * @return the service object or <code>null</code> if the service reference
+ * is no more valid or if the service object is not accessible.
+ * @see org.osgi.framework.BundleContext#getService(org.osgi.framework.ServiceReference)
+ */
+ public <S> S getService(ServiceReference<S> ref) {
+ //TODO Move this somewhere else
+ if (ref instanceof TransformedServiceReference) {
+ ref = ((TransformedServiceReference<S>) ref).getWrappedReference();
+ }
+ if (m_serviceContext == null) {
+ return m_bundleContext.getService(ref);
+ } else {
+ return (S) m_serviceContext.getService(ref);
+ }
+ }
+
+ /**
+ * Gets a service reference for the given interface.
+ * This method uses the service context if specified, the bundle
+ * context otherwise.
+ * @param clazz the required interface name
+ * @return a service reference on a available provider or <code>null</code>
+ * if no providers available
+ * @see org.osgi.framework.BundleContext#getServiceReference(java.lang.String)
+ */
+ public ServiceReference getServiceReference(String clazz) {
+ if (m_serviceContext == null) {
+ return m_bundleContext.getServiceReference(clazz);
+ } else {
+ return m_serviceContext.getServiceReference(clazz);
+ }
+ }
+
+ /**
+ * Gets a service reference for the given interface.
+ * This method uses the service context if specified, the bundle
+ * context otherwise.
+ * @param sClass the required interface class
+ * @param <S> the service class
+ * @return a service reference on a available provider or <code>null</code>
+ * if no providers available
+ * @see org.osgi.framework.BundleContext#getServiceReference(java.lang.String)
+ */
+ public <S> ServiceReference<S> getServiceReference(Class<S> sClass) {
+ if (m_serviceContext == null) {
+ return m_bundleContext.getServiceReference(sClass);
+ } else {
+ return m_serviceContext.getServiceReference(sClass);
+ }
+ }
+
+ /**
+ * Gets service reference list for the given query.
+ * This method uses the service context if specified, the bundle
+ * context otherwise.
+ * @param sClass the name of the required service interface
+ * @param filter the LDAP filter to apply on service provider
+ * @param <S> the service class
+ * @return the array of consistent service reference or <code>null</code>
+ * if no available providers
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ */
+ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> sClass, String filter) throws InvalidSyntaxException {
+ if (m_serviceContext == null) {
+ return m_bundleContext.getServiceReferences(sClass, filter);
+ } else {
+ return m_serviceContext.getServiceReferences(sClass, filter);
+ }
+ }
+
+ /**
+ * Gets service reference list for the given query.
+ * This method uses the service context if specified, the bundle
+ * context otherwise.
+ * @param clazz the name of the required service interface
+ * @param filter the LDAP filter to apply on service provider
+ * @return the array of consistent service reference or <code>null</code>
+ * if no available providers
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#getServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ if (m_serviceContext == null) {
+ return m_bundleContext.getServiceReferences(clazz, filter);
+ } else {
+ return m_serviceContext.getServiceReferences(clazz, filter);
+ }
+ }
+
+ /**
+ * Installs a bundle.
+ * @param location the URL of the bundle to install
+ * @return the installed bundle
+ * @throws BundleException if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String)
+ */
+ public Bundle installBundle(String location) throws BundleException {
+ return m_bundleContext.installBundle(location);
+ }
+
+ /**
+ * Installs a bundle.
+ * @param location the URL of the bundle to install
+ * @param input the input stream to load the bundle.
+ * @return the installed bundle
+ * @throws BundleException if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String, java.io.InputStream)
+ */
+ public Bundle installBundle(String location, InputStream input) throws BundleException {
+ return m_bundleContext.installBundle(location, input);
+ }
+
+ /**
+ * Registers a service.
+ * This method uses the service context if specified (and so, registers
+ * the service in this service registry), the bundle context otherwise (the
+ * service will be available to every global instances).
+ * @param clazzes the interfaces provided by the service.
+ * @param service the service object.
+ * @param properties the service properties to publish
+ * @return the service registration for this service publication.
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) {
+ if (m_serviceContext == null) {
+ return m_bundleContext.registerService(clazzes, service, properties);
+ } else {
+ return m_serviceContext.registerService(clazzes, service, properties);
+ }
+ }
+
+ /**
+ * Registers a service.
+ * This method uses the service context if specified (and so, registers
+ * the service in this service registry), the bundle context otherwise (the
+ * service will be available to every global instances).
+ * @param clazz the interface provided by the service.
+ * @param service the the service object.
+ * @param properties the service properties to publish.
+ * @return the service registration for this service publication.
+ * @see org.osgi.framework.BundleContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String clazz, Object service, Dictionary properties) {
+ if (m_serviceContext == null) {
+ return m_bundleContext.registerService(clazz, service, properties);
+ } else {
+ return m_serviceContext.registerService(clazz, service, properties);
+ }
+ }
+
+ /**
+ * Removes a bundle listener.
+ * @param listener the listener to remove
+ * @see org.osgi.framework.BundleContext#removeBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void removeBundleListener(BundleListener listener) {
+ m_bundleContext.removeBundleListener(listener);
+ }
+
+ /**
+ * Removes a framework listener.
+ * @param listener the listener to remove
+ * @see org.osgi.framework.BundleContext#removeFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void removeFrameworkListener(FrameworkListener listener) {
+ m_bundleContext.removeFrameworkListener(listener);
+ }
+
+ /**
+ * Registers a service
+ * @param sClass the service class
+ * @param s the service object (must implement sClass)
+ * @param stringDictionary service properties
+ * @param <S> the Service Class (specification)
+ * @return the service registration
+ */
+ public <S> ServiceRegistration<S> registerService(Class<S> sClass, S s, Dictionary<String, ?> stringDictionary) {
+ if (m_serviceContext == null) {
+ return m_bundleContext.registerService(sClass, s, stringDictionary);
+ } else {
+ return m_serviceContext.registerService(sClass, s, stringDictionary);
+ }
+ }
+
+ /**
+ * Removes a service listener.
+ * Removes the service listener from where it was registered so either in
+ * the global context, or in the service context or in the internal dispatcher.
+ * @param listener the service listener to remove
+ * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ * @see org.osgi.framework.BundleContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void removeServiceListener(ServiceListener listener) {
+ if (m_serviceContext == null) {
+ EventDispatcher dispatcher = EventDispatcher.getDispatcher();
+ if (dispatcher == null || ! dispatcher.removeListener(listener)) {
+ m_bundleContext.removeServiceListener(listener);
+ }
+ } else {
+ m_serviceContext.removeServiceListener(listener);
+ }
+ }
+
+ /**
+ * Ungets the service reference.
+ * This method uses the service context if specified,
+ * the bundle context otherwise.
+ * @param reference the reference to unget
+ * @return <code>true</code> if you are the last user of the reference
+ * @see org.osgi.framework.BundleContext#ungetService(org.osgi.framework.ServiceReference)
+ */
+ public boolean ungetService(ServiceReference reference) {
+ //TODO Move this somewhere else
+ if (reference instanceof TransformedServiceReference) {
+ reference = ((TransformedServiceReference) reference).getWrappedReference();
+ }
+ if (m_serviceContext == null) {
+ return m_bundleContext.ungetService(reference);
+ } else {
+ return m_serviceContext.ungetService(reference);
+ }
+ }
+
+ /**
+ * Gets the global context, i.e. the bundle context of the factory.
+ * @return the global bundle context.
+ */
+ public BundleContext getGlobalContext() {
+ return m_bundleContext;
+ }
+
+ /**
+ * Gets the service context, i.e. the composite context.
+ * Returns <code>null</code> if the instance does not live
+ * inside a composite.
+ * @return the service context or <code>null</code>.
+ */
+ public ServiceContext getServiceContext() {
+ return m_serviceContext;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
new file mode 100644
index 0000000..97ca40a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
@@ -0,0 +1,1184 @@
+/*
+ * 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;
+
+import static java.lang.String.format;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.extender.internal.Extender;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.SecurityHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This class defines common mechanisms of iPOJO component factories
+ * (i.e. component type).
+ *
+ * The factory is also tracking Factory configuration from the configuration admin to created / delete and update
+ * instances from this factory.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class IPojoFactory implements Factory {
+ /*
+ * TODO there is potentially an issue when calling FactoryStateListener callbacks with the lock
+ * It should be called by a separate thread dispatching events to listeners.
+ */
+
+ /**
+ * The list of the managed instance name.
+ * This list is shared by all factories and is used to assert name uniqueness.
+ */
+ protected static final List<String> INSTANCE_NAME = Collections.synchronizedList(new ArrayList<String>());
+
+ /**
+ * The component type description exposed by the {@link Factory} service.
+ */
+ protected ComponentTypeDescription m_componentDesc;
+
+ /**
+ * The list of the managed instance managers.
+ * The key of this map is the name (i.e. instance names) of the created instance
+ */
+ protected final Map<String, ComponentInstance> m_componentInstances = new ConcurrentHashMap<String, ComponentInstance>();
+
+ /**
+ * The component type metadata.
+ */
+ protected final Element m_componentMetadata;
+
+ /**
+ * The bundle context reference.
+ */
+ protected final BundleContext m_context;
+
+ /**
+ * The factory name.
+ * Could be the component class name if the factory name is not set.
+ * Immutable once set.
+ */
+ protected String m_factoryName;
+
+ /**
+ * The list of required handlers.
+ */
+ protected final List<RequiredHandler> m_requiredHandlers = new ArrayList<RequiredHandler>();
+
+ /**
+ * The list of factory state listeners.
+ * @see FactoryStateListener
+ */
+ protected List<FactoryStateListener> m_listeners = new ArrayList<FactoryStateListener>(1);
+
+ /**
+ * The logger for the factory.
+ */
+ protected final Logger m_logger;
+
+ /**
+ * Is the factory public (exposed as services).
+ */
+ protected final boolean m_isPublic;
+
+ /**
+ * The version of the component type.
+ */
+ protected final String m_version;
+
+ /**
+ * The service registration of this factory (Factory & ManagedServiceFactory).
+ * @see ManagedServiceFactory
+ * @see Factory
+ */
+ protected ServiceRegistration m_sr;
+
+ /**
+ * The factory state.
+ * Can be:
+ * <li>{@link Factory#INVALID}</li>
+ * <li>{@link Factory#VALID}</li>
+ * The factory is invalid at the beginning.
+ * A factory becomes valid if every required handlers
+ * are available (i.e. can be created).
+ */
+ protected int m_state = Factory.INVALID;
+
+ /**
+ * The flag indicating if this factory has already a
+ * computed description or not.
+ */
+ private boolean m_described;
+
+ /**
+ * Generates a unique instance name if not provided by the configuration.
+ */
+ private final NameGenerator m_generator = new RetryNameGenerator(new DefaultNameGenerator());
+
+ /**
+ * Creates an iPOJO Factory.
+ * At the end of this method, the required set of handler is computed.
+ * But the result is computed by a sub-class.
+ * @param context the bundle context of the bundle containing the factory.
+ * @param metadata the description of the component type.
+ * @throws ConfigurationException if the element describing the factory is malformed.
+ */
+ public IPojoFactory(BundleContext context, Element metadata) throws ConfigurationException {
+ m_context = context;
+ m_componentMetadata = metadata;
+ m_factoryName = getFactoryName();
+ String fac = metadata.getAttribute("public");
+ m_isPublic = fac == null || !fac.equalsIgnoreCase("false");
+ m_logger = new Logger(m_context, m_factoryName);
+
+ // Compute the component type version.
+ String version = metadata.getAttribute("version");
+ if ("bundle".equalsIgnoreCase(version)) { // Handle the "bundle" constant: use the bundle version.
+ // The cast is necessary in KF.
+ m_version = (String) m_context.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
+ } else {
+ m_version = version;
+ }
+
+ m_requiredHandlers.addAll(getRequiredHandlerList()); // Call sub-class to get the list of required handlers.
+
+ m_logger.log(Logger.INFO, "New factory created : " + m_factoryName);
+ }
+
+ /**
+ * Gets the component type description.
+ * @return the component type description
+ */
+ public ComponentTypeDescription getComponentTypeDescription() {
+ return new ComponentTypeDescription(this);
+ }
+
+ /**
+ * Adds a factory listener.
+ * @param listener the factory listener to add.
+ * @see org.apache.felix.ipojo.Factory#addFactoryStateListener(org.apache.felix.ipojo.FactoryStateListener)
+ */
+ public void addFactoryStateListener(FactoryStateListener listener) {
+ synchronized (this) {
+ m_listeners.add(listener);
+ }
+ }
+
+ /**
+ * Gets the logger used by instances created by the current factory.
+ * @return the factory logger.
+ */
+ public Logger getLogger() {
+ return m_logger;
+ }
+
+ /**
+ * Computes the factory name.
+ * Each sub-type must override this method.
+ * @return the factory name.
+ */
+ public abstract String getFactoryName();
+
+ /**
+ * Computes the required handler list.
+ * Each sub-type must override this method.
+ * @return the required handler list
+ * @throws ConfigurationException when the list of handler cannot be computed.
+ */
+ public abstract List<RequiredHandler> getRequiredHandlerList() throws ConfigurationException;
+
+ /**
+ * Creates an instance.
+ * This method is called with the monitor lock.
+ * @param config the instance configuration
+ * @param context the iPOJO context to use
+ * @param handlers the handler array to use
+ * @return the new component instance.
+ * @throws ConfigurationException if the instance creation failed during the configuration process.
+ */
+ public abstract ComponentInstance createInstance(Dictionary config, IPojoContext context, HandlerManager[] handlers)
+ throws ConfigurationException;
+
+ /**
+ * Creates an instance.
+ * This method creates the instance in the global context.
+ * @param configuration the configuration of the created instance.
+ * @return the created component instance.
+ * @throws UnacceptableConfiguration if the given configuration is not consistent with the component type of this factory.
+ * @throws MissingHandlerException if an handler is unavailable when the instance is created.
+ * @throws org.apache.felix.ipojo.ConfigurationException if the instance or type configuration are not correct.
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
+ */
+ public ComponentInstance createComponentInstance(Dictionary configuration) throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+ return createComponentInstance(configuration, null);
+ }
+
+ /**
+ * Creates an instance in the specified service context.
+ * This method is synchronized to assert the validity of the factory during the creation.
+ * Callbacks to sub-class and created instances need to be aware that they are holding the monitor lock.
+ * This method call the override {@link IPojoFactory#createInstance(Dictionary, IPojoContext, HandlerManager[])}
+ * method.
+ * @param configuration the configuration of the created instance.
+ * @param serviceContext the service context to push for this instance.
+ * @return the created component instance.
+ * @throws UnacceptableConfiguration if the given configuration is not consistent with the component type of this factory.
+ * @throws MissingHandlerException if an handler is unavailable when creating the instance.
+ * @throws org.apache.felix.ipojo.ConfigurationException if the instance configuration failed.
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
+ */
+ public synchronized ComponentInstance createComponentInstance(Dictionary configuration, ServiceContext serviceContext) throws UnacceptableConfiguration, // NOPMD
+ MissingHandlerException, ConfigurationException {
+ if (configuration == null) {
+ configuration = new Properties();
+ }
+
+ IPojoContext context;
+ if (serviceContext == null) {
+ context = new IPojoContext(m_context);
+ } else {
+ context = new IPojoContext(m_context, serviceContext);
+ }
+
+ try {
+ checkAcceptability(configuration);
+ } catch (UnacceptableConfiguration e) {
+ m_logger.log(Logger.ERROR, "The configuration is not acceptable : " + e.getMessage());
+ throw new UnacceptableConfiguration("The configuration "
+ + configuration + " is not acceptable for " + m_factoryName
+ , e);
+ }
+
+ // Find name in the configuration
+ String name = findInstanceName(configuration);
+
+ // Execute name generation and verification in a synchronized block to ensure uniqueness
+ synchronized (INSTANCE_NAME) {
+ if (name != null) {
+ // Needs to ensure name uniqueness
+ if (INSTANCE_NAME.contains(name)) {
+ // name already in use, try to append factory's version
+ if (m_version != null) {
+ name = name + "-" + m_version;
+ if (INSTANCE_NAME.contains(name)) {
+ // It's still not unique
+ // We've done our best: throw an Exception
+ throw new UnacceptableConfiguration(format("%s : Instance name (suffixed with factory's version) \"%s\" is already used", getFactoryName(), name));
+ }
+ } else {
+ // No version provided: we cannot do more
+ throw new UnacceptableConfiguration(format("%s : Instance name (provided by the instance) \"%s\" is already used", getFactoryName(), name));
+ }
+ }
+ } else {
+ // Generated name is always unique, no verification required
+ name = m_generator.generate(this, INSTANCE_NAME);
+ }
+
+ // Reserve name
+ INSTANCE_NAME.add(name);
+ }
+
+ // Update name in configuration
+ configuration.put(Factory.INSTANCE_NAME_PROPERTY, name);
+
+ // Here we are sure to be valid until the end of the method.
+ HandlerManager[] handlers = new HandlerManager[m_requiredHandlers.size()];
+ for (int i = 0; i < handlers.length; i++) {
+ handlers[i] = getHandler(m_requiredHandlers.get(i), serviceContext);
+ }
+
+ try {
+ ComponentInstance instance = createInstance(configuration, context, handlers);
+ m_componentInstances.put(name, instance);
+ m_logger.log(Logger.INFO, "Instance " + name + " from factory " + m_factoryName + " created");
+ // Register the instance on the ConfigurationTracker to be updated if needed.
+ ConfigurationTracker.get().instanceCreated(instance);
+ return instance;
+ } catch (ConfigurationException e) {
+ INSTANCE_NAME.remove(name);
+ m_logger.log(Logger.ERROR, e.getMessage());
+ throw new ConfigurationException(e.getMessage(), e, m_factoryName);
+ }
+
+
+ }
+
+ private String findInstanceName(final Dictionary configuration) {
+ String name;
+ if (configuration.get(Factory.INSTANCE_NAME_PROPERTY) == null && configuration.get("name") == null) {
+ // No name provided
+ name = null;
+ } else {
+ // Support both instance.name & name
+ name = (String) configuration.get(Factory.INSTANCE_NAME_PROPERTY);
+ if (name == null) {
+ name = (String) configuration.get("name");
+ getLogger().log(Logger.WARNING, "The 'name' (" + name + ") attribute, used as the instance name, is deprecated, please use the 'instance.name' attribute");
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Gets the bundle context of the factory.
+ * @return the bundle context of the factory.
+ * @see org.apache.felix.ipojo.Factory#getBundleContext()
+ */
+ public BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ /**
+ * Gets the factory class name.
+ * @return the factory class name.
+ * @see org.apache.felix.ipojo.Factory#getClassName()
+ */
+ public abstract String getClassName();
+
+ /**
+ * Gets the component type description.
+ * @return the component type description object. <code>Null</code> if not already computed.
+ */
+ public ComponentTypeDescription getComponentDescription() {
+ return m_componentDesc;
+ }
+
+ /**
+ * Gets the component type description (Element-Attribute form).
+ * @return the component type description.
+ * @see org.apache.felix.ipojo.Factory#getDescription()
+ */
+ public Element getDescription() {
+ // Can be null, if not already computed.
+ if (m_componentDesc == null) {
+ return new Element("No description available for " + m_factoryName, "");
+ }
+ return m_componentDesc.getDescription();
+ }
+
+ /**
+ * Gets the component metadata.
+ * @return the component metadata
+ * @see org.apache.felix.ipojo.Factory#getComponentMetadata()
+ */
+ public Element getComponentMetadata() {
+ return m_componentMetadata;
+ }
+
+ /**
+ * Gets the list of instances created by the factory. The instances must be still alive.
+ *
+ * @return the list of created (and living) instances
+ * @since 1.11.0
+ */
+ public List<ComponentInstance> getInstances() {
+ // m_componentInstances is a concurrent hashmap, we can create retrieve values directly.
+ return new ArrayList<ComponentInstance>(m_componentInstances.values());
+ }
+
+ /**
+ * Gets the list of the names of the instances created by the factory. The instances must be still alive.
+ *
+ * @return the list of the names of created (and living) instances
+ * @since 1.11.0
+ */
+ public List<String> getInstancesNames() {
+ // m_componentInstances is a concurrent hashmap, we can create retrieve values directly.
+ return new ArrayList<String>(m_componentInstances.keySet());
+ }
+
+ /**
+ * Computes the list of missing handlers.
+ * @return the list of missing handlers.
+ * @see org.apache.felix.ipojo.Factory#getMissingHandlers()
+ */
+ public List<String> getMissingHandlers() {
+ List<String> list = new ArrayList<String>();
+ for (RequiredHandler req : m_requiredHandlers) {
+ if (req.getReference() == null) {
+ list.add(req.getFullName());
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Gets the factory name.
+ * This name is immutable once set.
+ * @return the factory name.
+ * @see org.apache.felix.ipojo.Factory#getName()
+ */
+ public String getName() {
+ return m_factoryName;
+ }
+
+ /**
+ * Gets the list of required handlers.
+ * The required handler list cannot change.
+ * @return the list of required handlers.
+ * @see org.apache.felix.ipojo.Factory#getRequiredHandlers()
+ */
+ public List<String> getRequiredHandlers() {
+ List<String> list = new ArrayList<String>();
+ for (RequiredHandler req : m_requiredHandlers) {
+ list.add(req.getFullName());
+ }
+ return list;
+ }
+
+ /**
+ * Gets the actual factory state.
+ * Must be synchronized as this state is dependent of handler availability.
+ * @return the actual factory state.
+ * @see org.apache.felix.ipojo.Factory#getState()
+ */
+ public synchronized int getState() {
+ return m_state;
+ }
+
+ /**
+ * Gets a component instance created by the current factory.
+ * @param name the instance name
+ * @return the component instance, {@literal null} if not found
+ */
+ public ComponentInstance getInstanceByName(String name) {
+ return m_componentInstances.get(name);
+ }
+
+ /**
+ * Checks if the configuration is acceptable.
+ * @param conf the configuration to test.
+ * @return <code>true</code> if the configuration is acceptable.
+ * @see org.apache.felix.ipojo.Factory#isAcceptable(java.util.Dictionary)
+ */
+ public boolean isAcceptable(Dictionary conf) {
+ try {
+ checkAcceptability(conf);
+ } catch (MissingHandlerException e) {
+ return false;
+ } catch (UnacceptableConfiguration e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the configuration is acceptable.
+ * This method checks the following assertions:
+ * <li>All handlers can be creates</li>
+ * <li>The configuration does not override immutable properties</li>
+ * <li>The configuration contains a value for every unvalued property</li>
+ * @param conf the configuration to test.
+ * @throws UnacceptableConfiguration if the configuration is unacceptable.
+ * @throws MissingHandlerException if an handler is missing.
+ */
+ public void checkAcceptability(Dictionary<String, ?> conf) throws UnacceptableConfiguration,
+ MissingHandlerException {
+ PropertyDescription[] props;
+ synchronized (this) {
+ if (m_state == Factory.INVALID) {
+ throw new MissingHandlerException(getMissingHandlers());
+ }
+ props = m_componentDesc.getProperties(); // Stack confinement.
+ // The property list is up to date, as the factory is valid.
+ }
+
+ // Check that the configuration does not override immutable properties.
+
+ for (PropertyDescription prop : props) {
+ // Is the property immutable
+ if (prop.isImmutable() && conf.get(prop.getName()) != null) {
+ throw new UnacceptableConfiguration("The property " + prop + " cannot be overridden : immutable " +
+ "property"); // The instance configuration tries to override an immutable property.
+ }
+ // Is the property required ?
+ if (prop.isMandatory() && prop.getValue() == null && conf.get(prop.getName()) == null) {
+ throw new UnacceptableConfiguration("The mandatory property " + prop.getName() + " is missing"); // The property must be set.
+ }
+ }
+ }
+
+ /**
+ * Reconfigures an existing instance.
+ * The acceptability of the configuration is checked before the reconfiguration. Moreover,
+ * the configuration must contain the 'instance.name' property specifying the instance
+ * to reconfigure.
+ * This method is synchronized to assert the validity of the factory during the reconfiguration.
+ * @param properties the new configuration to push.
+ * @throws UnacceptableConfiguration if the new configuration is not consistent with the component type.
+ * @throws MissingHandlerException if the current factory is not valid.
+ * @see org.apache.felix.ipojo.Factory#reconfigure(java.util.Dictionary)
+ */
+ public synchronized void reconfigure(Dictionary properties) throws UnacceptableConfiguration, MissingHandlerException {
+ if (properties == null || (properties.get(Factory.INSTANCE_NAME_PROPERTY) == null && properties.get("name") == null)) { // Support both instance.name and name
+ throw new UnacceptableConfiguration("The configuration does not contains the \"instance.name\" property");
+ }
+
+ String name = (String) properties.get(Factory.INSTANCE_NAME_PROPERTY);
+ if (name == null) {
+ name = (String) properties.get("name");
+ }
+
+ ComponentInstance instance = m_componentInstances.get(name);
+ if (instance == null) { // The instance does not exists.
+ return;
+ }
+
+ checkAcceptability(properties); // Test if the configuration is acceptable
+ instance.reconfigure(properties); // re-configure the instance
+ }
+
+ /**
+ * Removes a factory listener.
+ * @param listener the factory listener to remove.
+ * @see org.apache.felix.ipojo.Factory#removeFactoryStateListener(org.apache.felix.ipojo.FactoryStateListener)
+ */
+ public void removeFactoryStateListener(FactoryStateListener listener) {
+ synchronized (this) {
+ m_listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Stopping method.
+ * This method is call when the factory is stopping.
+ * This method is called when holding the lock on the factory.
+ */
+ public abstract void stopping();
+
+ /**
+ * Stops all the instance managers.
+ * This method calls the {@link IPojoFactory#stopping()} method,
+ * notifies listeners, and disposes created instances. Moreover,
+ * if the factory is public, services are also unregistered.
+ *
+ */
+ public synchronized void stop() {
+ ComponentInstance[] instances;
+ if (m_sr != null) {
+ m_sr.unregister();
+ m_sr = null;
+ }
+
+ ConfigurationTracker.get().unregisterFactory(this);
+
+ stopping(); // Method called when holding the lock.
+ int oldState = m_state; // Create a variable to store the old state. Using a variable is important as
+ // after the next instruction, the getState() method must return INVALID.
+ m_state = INVALID; // Set here to avoid to create instances during the stops.
+
+ Set<String> col = m_componentInstances.keySet();
+ Iterator<String> it = col.iterator();
+ instances = new ComponentInstance[col.size()]; // Stack confinement
+ int index = 0;
+ while (it.hasNext()) {
+ instances[index] = m_componentInstances.get(it.next());
+ index++;
+ }
+
+ if (oldState == VALID) { // Check if the old state was valid.
+ for (FactoryStateListener listener : m_listeners) {
+ listener.stateChanged(this, INVALID);
+ }
+ }
+
+ // Dispose created instances.
+ for (ComponentInstance instance : instances) {
+ if (instance.getState() != ComponentInstance.DISPOSED) {
+ instance.dispose();
+ }
+ }
+
+ // Release each handler
+ for (RequiredHandler req : m_requiredHandlers) {
+ req.unRef();
+ }
+
+ m_described = false;
+ m_componentDesc = null;
+ m_componentInstances.clear();
+
+ m_logger.log(Logger.INFO, "Factory " + m_factoryName + " stopped");
+
+ }
+
+ /**
+ * Destroys the factory.
+ * The factory cannot be restarted. Only the {@link Extender} can call this method.
+ */
+ public synchronized void dispose() {
+ // Fast exit if already disposed
+ // The m_listeners field is ONLY set to null after dispose(), so if it's null, that
+ // means the factory has already be disposed. We can return safely.
+ if (m_listeners == null) {
+ return;
+ }
+ stop(); // Does not hold the lock.
+ m_requiredHandlers.clear();
+ m_listeners = null;
+ }
+
+ /**
+ * Starting method.
+ * This method is called when the factory is starting.
+ * This method is <strong>not</strong> called when holding the lock on the factory.
+ */
+ public abstract void starting();
+
+ /**
+ * Starts the factory.
+ * Tries to compute the component type description,
+ * calls the {@link IPojoFactory#starting()} method,
+ * and published services if the factory is public.
+ */
+ public void start() {
+ synchronized (this) {
+ if (m_described) { // Already started.
+ return;
+ }
+ }
+
+ m_componentDesc = getComponentTypeDescription();
+
+ starting();
+
+ synchronized (this) {
+ computeFactoryState();
+ }
+
+ if (m_isPublic) {
+ // Exposition of the factory service
+ if (m_componentDesc == null) {
+ m_logger.log(Logger.ERROR, "Unexpected state, the description of " + m_factoryName + " is null");
+ return;
+ }
+ BundleContext bc = SecurityHelper.selectContextToRegisterServices(m_componentDesc.getFactoryInterfacesToPublish(),
+ m_context, getIPOJOBundleContext());
+ if (SecurityHelper.canRegisterService(bc)) {
+ m_sr =
+ bc.registerService(m_componentDesc.getFactoryInterfacesToPublish(), this, m_componentDesc
+ .getPropertiesToPublish());
+ m_logger.log(Logger.INFO, "Factory " + m_factoryName + " started");
+ } else {
+ m_logger.log(Log.ERROR, "Cannot register the Factory service with the bundle context of the bundle "
+ + bc.getBundle().getBundleId() + " - the bundle is in the state " + bc.getBundle().getState()
+ );
+ }
+ }
+ }
+
+ /**
+ * For testing purpose <b>ONLY</b>.
+ * This method recomputes the required handler list.
+ */
+ public void restart() {
+ // Call sub-class to get the list of required handlers.
+ m_requiredHandlers.clear();
+ try {
+ m_requiredHandlers.addAll(getRequiredHandlerList());
+ } catch (ConfigurationException e) {
+ // Swallow the exception.
+ }
+ }
+
+ /**
+ * Gets the iPOJO Bundle Context.
+ * @return the iPOJO Bundle Context
+ */
+ protected final BundleContext getIPOJOBundleContext() {
+ return Extender.getIPOJOBundleContext();
+ }
+
+ /**
+ * Creates or updates an instance.
+ * This method is used from the configuration tracker.
+ * @param name the name of the instance
+ * @param properties the new configuration of the instance
+ */
+ public void updated(String name, Dictionary properties) throws org.osgi.service.cm
+ .ConfigurationException {
+ ComponentInstance instance;
+ synchronized (this) {
+ instance = m_componentInstances.get(name);
+ }
+
+ if (instance == null) {
+ try {
+ properties.put(Factory.INSTANCE_NAME_PROPERTY, name); // Add the name in the configuration
+ // If an instance with this name was created before, this creation will failed.
+ createComponentInstance(properties);
+ } catch (UnacceptableConfiguration e) {
+ m_logger.log(Logger.ERROR, "The configuration is not acceptable : " + e.getMessage());
+ throw new org.osgi.service.cm.ConfigurationException(properties.toString(), e.getMessage(), e);
+ } catch (MissingHandlerException e) {
+ m_logger.log(Logger.ERROR, "Handler not available : " + e.getMessage());
+ throw new org.osgi.service.cm.ConfigurationException(properties.toString(), e.getMessage(), e);
+ } catch (ConfigurationException e) {
+ m_logger.log(Logger.ERROR, "The Component Type metadata are not correct : " + e.getMessage());
+ throw new org.osgi.service.cm.ConfigurationException(properties.toString(), e.getMessage(), e);
+ }
+ } else {
+ try {
+ properties.put(Factory.INSTANCE_NAME_PROPERTY, name); // Add the name in the configuration
+ reconfigure(properties); // re-configure the component
+ } catch (UnacceptableConfiguration e) {
+ m_logger.log(Logger.ERROR, "The configuration is not acceptable : " + e.getMessage());
+ throw new org.osgi.service.cm.ConfigurationException(properties.toString(), e.getMessage(), e);
+ } catch (MissingHandlerException e) {
+ m_logger.log(Logger.ERROR, "The factory is not valid, at least one handler is missing : " + e.getMessage());
+ throw new org.osgi.service.cm.ConfigurationException(properties.toString(), e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Deletes an instance.
+ * @param name the name of the instance to delete
+ */
+ public synchronized void deleted(String name) {
+ INSTANCE_NAME.remove(name);
+ ComponentInstance instance = m_componentInstances.remove(name);
+ if (instance != null) {
+ instance.dispose();
+ }
+ }
+
+ /**
+ * Callback called by instance when disposed.
+ * @param instance the destroyed instance
+ */
+ public void disposed(ComponentInstance instance) {
+ String name = instance.getInstanceName();
+ m_componentInstances.remove(name);
+ INSTANCE_NAME.remove(name);
+ }
+
+ /**
+ * Computes the component type description.
+ * To do this, it creates a 'ghost' instance of the handler
+ * and calls the {@link Handler#initializeComponentFactory(ComponentTypeDescription, Element)}
+ * method. The handler instance is then deleted.
+ * The factory must be valid when calling this method.
+ * This method is called with the lock.
+ */
+ protected void computeDescription() {
+ for (RequiredHandler req : m_requiredHandlers) {
+ HandlerManager handlerManager = null;
+ try {
+ handlerManager = getHandler(req, null);
+ } catch (Exception e) {
+ m_logger.log(Logger.ERROR, "Cannot extract handler object from " + m_factoryName + " " + req
+ .getFullName());
+ return;
+ }
+
+ if (handlerManager == null) {
+ m_logger.log(Logger.ERROR, "Cannot extract handler object from " + m_factoryName + " " + req
+ .getFullName());
+ return;
+ }
+
+ Handler handler = handlerManager.getHandler();
+ try {
+ handler.setFactory(this);
+ handler.initializeComponentFactory(m_componentDesc, m_componentMetadata);
+ ((Pojo) handler).getComponentInstance().dispose();
+ } catch (ConfigurationException e) {
+ ((Pojo) handler).getComponentInstance().dispose();
+ m_logger.log(Logger.ERROR, e.getMessage());
+ stop();
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ /**
+ * Computes factory state.
+ * The factory is valid if every required handler are available.
+ * If the factory becomes valid for the first time, the component
+ * type description is computed.
+ * This method is called when holding the lock on the current factory.
+ */
+ protected void computeFactoryState() {
+ boolean isValid = true;
+ for (RequiredHandler req : m_requiredHandlers) {
+ if (req.getReference() == null) {
+ isValid = false;
+ break;
+ }
+
+ }
+
+ if (isValid) {
+ if (m_state == INVALID) {
+
+ if (!m_described) {
+ computeDescription();
+ m_described = true;
+ }
+
+ m_state = VALID;
+ if (m_sr != null) {
+ if (SecurityHelper.canUpdateService(m_sr)) {
+ m_sr.setProperties(m_componentDesc.getPropertiesToPublish());
+ }
+ }
+
+ // Register the factory on the ConfigurationTracker
+ ConfigurationTracker.get().registerFactory(this);
+
+ for (FactoryStateListener listener : m_listeners) {
+ listener.stateChanged(this, VALID);
+ }
+ }
+ } else {
+ if (m_state == VALID) {
+ m_state = INVALID;
+
+ // Un-register the factory on the ConfigurationTracker
+ ConfigurationTracker.get().unregisterFactory(this);
+
+ // Notify listeners.
+ for (FactoryStateListener listener : m_listeners) {
+ listener.stateChanged(this, INVALID);
+ }
+
+ // Dispose created instances.
+ // We must create a copy to avoid concurrent exceptions
+ Set<? extends String> keys = new HashSet<String>(m_componentInstances.keySet());
+ for (String key : keys) {
+ ComponentInstance instance = m_componentInstances.get(key);
+ if (instance.getState() != ComponentInstance.DISPOSED) {
+ instance.dispose();
+ }
+ INSTANCE_NAME.remove(instance.getInstanceName());
+ }
+
+ m_componentInstances.clear();
+
+ if (SecurityHelper.canUpdateService(m_sr)) {
+ // No null check required as the security helper is checking this too.
+ m_sr.setProperties(m_componentDesc.getPropertiesToPublish());
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the given handler identifier and the service reference match.
+ * Does not need to be synchronized as the method does not use any fields.
+ * @param req the handler identifier.
+ * @param ref the service reference.
+ * @return <code>true</code> if the service reference can fulfill the handler requirement
+ */
+ protected boolean match(RequiredHandler req, ServiceReference<?> ref) {
+ String name = (String) ref.getProperty(Handler.HANDLER_NAME_PROPERTY);
+ String namespace = (String) ref.getProperty(Handler.HANDLER_NAMESPACE_PROPERTY);
+ if (HandlerFactory.IPOJO_NAMESPACE.equals(namespace)) {
+ return name.equalsIgnoreCase(req.getName()) && req.getNamespace() == null;
+ }
+ return name.equalsIgnoreCase(req.getName()) && namespace.equalsIgnoreCase(req.getNamespace());
+ }
+
+ /**
+ * Returns the handler object for the given required handler.
+ * The handler is instantiated in the given service context.
+ * This method is called with the lock.
+ * @param req the handler to create.
+ * @param context the service context in which the handler is created (same as the instance context).
+ * @return the handler object.
+ */
+ protected HandlerManager getHandler(RequiredHandler req, ServiceContext context) throws MissingHandlerException,
+ UnacceptableConfiguration, ConfigurationException {
+ try {
+ return (HandlerManager) req.getFactory().createComponentInstance(null, context);
+ } catch (MissingHandlerException e) {
+ m_logger.log(Logger.ERROR, "The creation of the handler " + req.getFullName() + " has failed: " + e.getMessage());
+ stop();
+ throw e;
+ } catch (UnacceptableConfiguration e) {
+ m_logger.log(Logger.ERROR, "The creation of the handler "
+ + req.getFullName()
+ + " has failed (UnacceptableConfiguration): "
+ + e.getMessage());
+ stop();
+ throw e;
+ } catch (org.apache.felix.ipojo.ConfigurationException e) {
+ m_logger.log(Logger.ERROR, "The configuration of the handler "
+ + req.getFullName()
+ + " has failed (ConfigurationException): "
+ + e.getMessage());
+ stop();
+ throw e;
+ }
+ }
+
+ /**
+ * Structure storing required handlers.
+ * Access to this class must mostly be with the lock on the factory.
+ * (except to access final fields)
+ */
+ protected class RequiredHandler implements Comparable {
+ /**
+ * The factory to create this handler.
+ */
+ private HandlerFactory m_factory;
+
+ /**
+ * The handler name.
+ */
+ private final String m_name;
+
+ /**
+ * The handler start level.
+ */
+ private int m_level = Integer.MAX_VALUE;
+
+ /**
+ * The handler namespace.
+ */
+ private final String m_namespace;
+
+ /**
+ * The Service Reference of the handler factory.
+ */
+ private ServiceReference<? extends HandlerFactory> m_reference;
+
+ /**
+ * Crates a Required Handler.
+ * @param name the handler name.
+ * @param namespace the handler namespace.
+ */
+ public RequiredHandler(String name, String namespace) {
+ m_name = name;
+ m_namespace = namespace;
+ }
+
+ /**
+ * Equals method.
+ * Two handlers are equals if they have same name and namespace or they share the same service reference.
+ * @param object the object to compare to the current object.
+ * @return <code>true</code> if the two compared object are equals
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object object) {
+ if (object instanceof RequiredHandler) {
+ RequiredHandler req = (RequiredHandler) object;
+ if (m_namespace == null) {
+ return req.m_name.equalsIgnoreCase(m_name) && req.m_namespace == null;
+ } else {
+ return req.m_name.equalsIgnoreCase(m_name) && m_namespace.equalsIgnoreCase(req.m_namespace);
+ }
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * Hashcode method.
+ * This method delegates to the {@link Object#hashCode()}.
+ * @return the object hashcode.
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Gets the factory object used for this handler.
+ * The object is get when used for the first time.
+ * This method is called with the lock avoiding concurrent modification and on a valid factory.
+ * @return the factory object.
+ */
+ public HandlerFactory getFactory() {
+ if (m_reference == null) {
+ return null;
+ }
+ if (m_factory == null) {
+ m_factory = m_context.getService(getReference());
+ }
+ return m_factory;
+ }
+
+ /**
+ * Gets the handler qualified name (<code>namespace:name</code>).
+ * @return the handler full name
+ */
+ public String getFullName() {
+ if (m_namespace == null) {
+ return HandlerFactory.IPOJO_NAMESPACE + ":" + m_name;
+ } else {
+ return m_namespace + ":" + m_name;
+ }
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public String getNamespace() {
+ return m_namespace;
+ }
+
+ public ServiceReference<? extends HandlerFactory> getReference() {
+ return m_reference;
+ }
+
+ public int getLevel() {
+ return m_level;
+ }
+
+ /**
+ * Releases the reference of the used factory.
+ * This method is called with the lock on the current factory.
+ */
+ public void unRef() {
+ if (m_reference != null) {
+ m_factory = null;
+ m_reference = null;
+ }
+ }
+
+ /**
+ * Sets the service reference. If the new service reference is <code>null</code>, it ungets the used factory (if already get).
+ * This method is called with the lock on the current factory.
+ * @param ref the new service reference.
+ */
+ public void setReference(ServiceReference<? extends HandlerFactory> ref) {
+ m_reference = ref;
+ Integer level = (Integer) m_reference.getProperty(Handler.HANDLER_LEVEL_PROPERTY);
+ if (level != null) {
+ m_level = level;
+ }
+ }
+
+ /**
+ * Start level Comparison.
+ * This method is used to sort the handler array.
+ * This method is called with the lock.
+ * @param object the object on which compare.
+ * @return <code>-1</code>, <code>0</code>, <code>+1</code> according to the comparison of their start levels.
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object object) {
+ if (object instanceof RequiredHandler) {
+ RequiredHandler req = (RequiredHandler) object;
+ if (this.m_level == req.m_level) {
+ return 0;
+ } else if (this.m_level < req.m_level) {
+ return -1;
+ } else {
+ return +1;
+ }
+ }
+ return 0;
+ }
+ }
+
+
+ /**
+ * This generator implements the default naming strategy.
+ * The name is composed of the factory name suffixed with a unique number identifier (starting from 0).
+ */
+ public static class DefaultNameGenerator implements NameGenerator {
+
+ private AtomicLong m_nextId = new AtomicLong();
+
+ public String generate(Factory factory, List<String> reserved) throws UnacceptableConfiguration {
+ StringBuilder sb = new StringBuilder();
+ sb.append(factory.getName());
+ if (factory.getVersion() != null) {
+ sb.append("/");
+ sb.append(factory.getVersion());
+ }
+ sb.append("-");
+ sb.append(m_nextId.getAndIncrement());
+ return sb.toString();
+ }
+ }
+
+ /**
+ * This generator implements a retry naming strategy.
+ * It uses a delegate {@link org.apache.felix.ipojo.IPojoFactory.NameGenerator}, and call it in sequence until an unused value is found.
+ */
+ public static class RetryNameGenerator implements NameGenerator {
+
+ private final NameGenerator m_delegate;
+
+ /**
+ * Bound the loop to avoid Stack overflows
+ */
+ private long maximum = 8096;
+
+ public RetryNameGenerator(final NameGenerator delegate) {
+ m_delegate = delegate;
+ }
+
+ public void setMaximum(final long maximum) {
+ this.maximum = maximum;
+ }
+
+ public String generate(final Factory factory, final List<String> reserved) throws UnacceptableConfiguration {
+ // Loop until we obtain a unique value (or counter overflow)
+ long counter = 0;
+ while (counter < maximum) {
+ String generated = m_delegate.generate(factory, reserved);
+ counter++;
+ // Verify uniqueness
+ if (!reserved.contains(generated)) {
+ return generated;
+ }
+ }
+
+ // Should never happen (except is NameGenerator composition is broken: like a delegate that
+ // never change its return value)
+ throw new UnacceptableConfiguration(format("Cannot generate unique instance name for factory %s/%s from bundle %d",
+ factory.getName(),
+ factory.getVersion(),
+ factory.getBundleContext().getBundle().getBundleId()));
+ }
+ }
+
+ /**
+ * Generate a unique name for a component instance.
+ */
+ public static interface NameGenerator {
+
+ /**
+ * @return a unique name.
+ * @param factory Factory called to create the instance
+ * @param reserved List of reserved (already used) instance names.
+ * This has to be used tp ensure generated name is unique among all other instances.
+ */
+ String generate(Factory factory, List<String> reserved) throws UnacceptableConfiguration;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
new file mode 100644
index 0000000..6de586e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
@@ -0,0 +1,1578 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.extender.internal.linker.InstanceBundleContextAware;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.Property;
+import org.osgi.framework.BundleContext;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This class defines the container of primitive instances. It manages content initialization
+ * and handlers cooperation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstanceManager implements ComponentInstance, InstanceStateListener, InstanceBundleContextAware {
+ /**
+ * The name of the component instance.
+ */
+ protected String m_name;
+
+ /**
+ * The name of the component type implementation class.
+ */
+ protected String m_className;
+
+ /**
+ * The handler object list.
+ */
+ protected final HandlerManager[] m_handlers;
+
+ /**
+ * The current instance state ({@link ComponentInstance#STOPPED} at the beginning).
+ * Possible value are
+ * <li>{@link ComponentInstance#INVALID}</li>
+ * <li>{@link ComponentInstance#VALID}</li>
+ * <li>{@link ComponentInstance#DISPOSED}</li>
+ * <li>{@link ComponentInstance#STOPPED}</li>
+ */
+ protected int m_state = STOPPED;
+
+ /**
+ * The instance state listener list.
+ *
+ * @see InstanceStateListener
+ */
+ protected List m_listeners = null;
+
+ /**
+ * The content of the current instance.
+ */
+ protected List m_pojoObjects;
+
+ /**
+ * The instance factory.
+ */
+ private final ComponentFactory m_factory;
+
+ /**
+ * The instance logger.
+ */
+ private final Logger m_logger;
+
+ /**
+ * The instance description.
+ */
+ private final PrimitiveInstanceDescription m_description;
+
+ /**
+ * The bundle context of the instance.
+ */
+ private final BundleContext m_context;
+
+ /**
+ * The map [field, {@link FieldInterceptor} list] storing interceptors monitoring fields.
+ * Once configured, this map can't change.
+ */
+ private Map m_fieldRegistration;
+
+ /**
+ * the map [method identifier, {@link MethodInterceptor} list] interested
+ * by the method.
+ * Once configured, this map can't change.
+ */
+ private Map m_methodRegistration;
+
+ /**
+ * the map (sorted by parameter index) or {@link ConstructorInjector} interested by
+ * injecting constructor parameter.
+ * Once configured, this list can't change.
+ */
+ private Map m_constructorRegistration;
+
+ /**
+ * The manipulated class.
+ * Once set, this field doesn't change.
+ */
+ private Class m_clazz;
+
+ /**
+ * The factory method used to create content objects.
+ * If <code>null</code>, the regular constructor is used.
+ * Once set, this field is immutable.
+ */
+ private String m_factoryMethod = null;
+
+ /**
+ * Is the component instance state changing?
+ */
+ private boolean m_inTransition = false;
+
+ /**
+ * The queue of stored state changed.
+ */
+ private List m_stateQueue = new ArrayList();
+
+ /**
+ * The map of [field, value], storing POJO managed
+ * field value.
+ */
+ private Map m_fields = new HashMap();
+
+ /**
+ * The Map storing the Method objects by ids.
+ * [id=>{@link Method}].
+ */
+ private Map m_methods = Collections.synchronizedMap(new HashMap());
+
+ /**
+ * The instance's bundle context.
+ */
+ private BundleContext m_instanceContext;
+
+
+ /**
+ * Creates a new Component Manager.
+ * The instance is not initialized.
+ *
+ * @param factory the factory managing the instance manager
+ * @param context the bundle context to give to the instance
+ * @param handlers handler object array
+ */
+ public InstanceManager(ComponentFactory factory, BundleContext context, HandlerManager[] handlers) {
+ m_factory = factory;
+ m_context = context;
+ m_handlers = handlers;
+ m_description = new PrimitiveInstanceDescription(m_factory.getComponentDescription(), this);
+ m_logger = new Logger(m_context, this);
+ }
+
+ /**
+ * Sets the instance bundle context.
+ *
+ * @param context the bundle context of the bundle having declared the instance
+ * @since 1.11.2
+ */
+ public void setInstanceBundleContext(BundleContext context) {
+ m_instanceContext = context;
+ }
+
+ /**
+ * The instance logger.
+ *
+ * @return the logger
+ */
+ public Logger getLogger() {
+ return m_logger;
+ }
+
+ /**
+ * Configures the instance manager.
+ * Sets the class name, and the instance name as well as the factory method.
+ * Initializes handlers.
+ *
+ * @param metadata the component type metadata
+ * @param configuration the configuration of the instance
+ * @throws ConfigurationException if the metadata are not correct
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ m_className = metadata.getAttribute("classname");
+
+ // Add the name
+ m_name = (String) configuration.get(Factory.INSTANCE_NAME_PROPERTY);
+
+ // Check if an object is injected in the instance
+ Object obj = configuration.get("instance.object");
+ if (obj != null) {
+ m_pojoObjects = new ArrayList(1);
+ m_pojoObjects.add(obj);
+ }
+
+ // Get the factory method if presents.
+ m_factoryMethod = (String) metadata.getAttribute("factory-method");
+
+ // Check if we have an instance bundle context given as property, it should not be used,
+ // but it's a way to provide the instance bundle context when using the Factory service.
+ // The instance context is set only if it was not already set.
+ if (m_instanceContext == null) {
+ m_instanceContext = (BundleContext) configuration.get("instance.bundle.context");
+ }
+
+ // Create the standard handlers and add these handlers to the list
+ for (HandlerManager handler : m_handlers) {
+ handler.init(this, metadata, configuration);
+ }
+
+
+ // Fix for Felix-3576
+ handleBCInjections();
+
+
+ // Check that the constructor parameter are continuous.
+ if (m_constructorRegistration != null) {
+ for (int i = 0; i < m_constructorRegistration.size(); i++) {
+ if (!m_constructorRegistration.containsKey(i)) {
+ throw new ConfigurationException("The constructor parameter " + i + " is not managed");
+ }
+ }
+ }
+ }
+
+ /**
+ * BundleContext injection is not registered with the InstanceManager.
+ * We're iterating through factory's all constructors and register first
+ * BundleContext parameter as constructor injection. So rest of the code
+ * don't have to do anything to handle BundleContext mixed with other
+ * injections.
+ *
+ * @throws ConfigurationException
+ */
+ private void handleBCInjections() throws ConfigurationException {
+ MethodMetadata[] constructors = getFactory().getPojoMetadata().getConstructors();
+ for (MethodMetadata constructor : constructors) {
+ String[] ctorArguments = constructor.getMethodArguments();
+
+ for (int index = 0; index < ctorArguments.length; index++) {
+ if (ctorArguments[index].equals(BundleContext.class.getName())
+ && (m_constructorRegistration == null || !m_constructorRegistration.containsKey(index))) {
+ //Check if its used with only other injections.
+ boolean injectionsConsistent = true;
+ for (int siblingIndex = 0; siblingIndex < ctorArguments.length; siblingIndex++) {
+ if (siblingIndex == index) {
+ continue;
+ }
+
+ String injectionType = ctorArguments[siblingIndex];
+ if (m_constructorRegistration != null && m_constructorRegistration.containsKey(siblingIndex)) {
+ ConstructorInjector siblingInjector =
+ (ConstructorInjector) m_constructorRegistration.get(siblingIndex);
+ Class injectorClass = siblingInjector.getConstructorParameterType(siblingIndex);
+
+ if (injectorClass != null && !injectorClass.getName().equals(injectionType)) {
+ injectionsConsistent = false;
+ break;
+ }
+ } else {
+ injectionsConsistent = false;
+ break;
+ }
+ }
+
+ if (injectionsConsistent) {
+ Property contextInjection =
+ new Property("__context", null, null, index, null,
+ BundleContext.class.getName(), this, null);
+
+ contextInjection.setValue(getContext());
+ register(index, contextInjection);
+
+ // We register the first valid BC injection.
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the description of the current instance.
+ *
+ * @return the instance description.
+ * @see org.apache.felix.ipojo.ComponentInstance#getInstanceDescription()
+ */
+ public InstanceDescription getInstanceDescription() {
+ return m_description;
+ }
+
+ /**
+ * Gets the list of handlers plugged (i.e. attached) on the instance.
+ * This method does not need a synchronized block as the handler set is constant.
+ *
+ * @return the handler array of plugged handlers.
+ */
+ public Handler[] getRegisteredHandlers() {
+ Handler[] handler = new Handler[m_handlers.length];
+ for (int i = 0; i < m_handlers.length; i++) {
+ handler[i] = m_handlers[i].getHandler();
+ }
+ return handler;
+ }
+
+ /**
+ * Returns a specified handler.
+ * This method allows cross-handler interactions.
+ * This must does not need a synchronized block as the handler set is constant.
+ *
+ * @param name the class name of the handler to find or its qualified name (namespace:name)
+ * @return the handler, or null if not found
+ */
+ public Handler getHandler(String name) {
+ for (int i = 0; i < m_handlers.length; i++) {
+ HandlerFactory fact = (HandlerFactory) m_handlers[i].getHandler().getHandlerManager().getFactory();
+ if (fact.getHandlerName().equals(name)) {
+ return m_handlers[i].getHandler();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gives access to a field value of the first created pojo.
+ * This method processes by analyzing both managed fields and pojo fields (by reflection).
+ * If no pojo were already created try only on managed fields.
+ *
+ * @param fieldName the field name.
+ * @return the field value, <code>null</code> is returned if the value is managed and not already set.
+ */
+ public synchronized Object getFieldValue(String fieldName) {
+ if (m_pojoObjects == null) {
+ return getFieldValue(fieldName, null);
+ } else {
+ return getFieldValue(fieldName, m_pojoObjects.get(0)); // Use the first pojo.
+ }
+ }
+
+ /**
+ * Gives access to a field value to the given created pojo.
+ * This method processes by analyzing both managed fields and pojo fields (by reflection).
+ * If the given pojo is <code>null</code>, tries only on managed fields.
+ *
+ * @param fieldName the field name.
+ * @param pojo the pojo on which computing field value.
+ * @return the field value, <code>null</code> is returned if the value is managed and not already set.
+ */
+ public synchronized Object getFieldValue(String fieldName, Object pojo) {
+ Object setByContainer = null;
+
+ if (m_fields != null) {
+ setByContainer = m_fields.get(fieldName);
+ }
+
+ if (setByContainer == null && pojo != null) { // In the case of no given pojo, return null.
+ // If null either the value was not already set or has the null value.
+ try {
+ Field field = pojo.getClass().getDeclaredField(fieldName);
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ return field.get(pojo);
+ } catch (SecurityException e) {
+ m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+ } catch (NoSuchFieldException e) {
+ m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
+ }
+ return null;
+ } else {
+ return setByContainer;
+ }
+ }
+
+ /**
+ * Starts the instance manager.
+ * This method activates plugged handlers,
+ * and computes the initial instance state.
+ */
+ public void start() {
+ synchronized (this) {
+ if (m_state != STOPPED) { // Instance already started
+ return;
+ } else {
+ m_state = -2; // Temporary state.
+ }
+ }
+
+ // Plug handler descriptions
+ Handler[] handlers = getRegisteredHandlers();
+ for (int i = 0; i < handlers.length; i++) {
+ m_description.addHandler(handlers[i].getDescription());
+ }
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].addInstanceStateListener(this);
+ try {
+ m_handlers[i].start();
+ } catch (IllegalStateException e) {
+ m_logger.log(Logger.ERROR, e.getMessage());
+ stop();
+ throw e;
+ }
+ }
+
+ // Is an object already contained (i.e. injected)
+ if (m_pojoObjects != null && !m_pojoObjects.isEmpty()) {
+ managedInjectedObject();
+ }
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getState() != VALID) {
+ setState(INVALID);
+ return;
+ }
+ }
+ setState(VALID);
+ }
+
+ /**
+ * Stops the instance manager.
+ * This methods sets the instance state to {@link ComponentInstance#STOPPED},
+ * disables attached handlers, and notifies listeners ({@link InstanceStateListener})
+ * of the instance stopping process.
+ */
+ public void stop() {
+ List listeners = null;
+ synchronized (this) {
+ if (m_state == STOPPED) { // Instance already stopped
+ return;
+ }
+ m_stateQueue.clear();
+ m_inTransition = false;
+ }
+
+ setState(INVALID); // Must be called outside a synchronized block.
+
+ // Stop all the handlers
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].removeInstanceStateListener(this);
+ m_handlers[i].stop();
+ }
+
+ synchronized (this) {
+ m_state = STOPPED;
+ if (m_listeners != null) {
+ listeners = new ArrayList(m_listeners); // Stack confinement
+ }
+ m_pojoObjects = null;
+ }
+
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ ((InstanceStateListener) listeners.get(i)).stateChanged(this, STOPPED);
+ }
+ }
+ }
+
+ /**
+ * Disposes the instance.
+ * This method does the following process:
+ * <li>Stop the instance is not {@link ComponentInstance#STOPPED}</li>
+ * <li>Notifies listeners {@link InstanceStateListener} of the destruction</li>
+ * <li>Disposes attached handlers</li>
+ * <li>Clears structures</li>
+ *
+ * @see org.apache.felix.ipojo.ComponentInstance#dispose()
+ */
+ public void dispose() {
+ List listeners = null;
+ int state; // Will be confined in stack.
+ synchronized (this) {
+ state = m_state; // Stack confinement
+ if (m_listeners != null) {
+ listeners = new ArrayList(m_listeners); // Stack confinement
+ }
+ m_listeners = null;
+ }
+
+ if (state > STOPPED) { // Valid or invalid
+ stop(); // Does not hold the lock.
+ }
+
+ synchronized (this) {
+ m_state = DISPOSED;
+ }
+
+ for (int i = 0; listeners != null && i < listeners.size(); i++) {
+ ((InstanceStateListener) listeners.get(i)).stateChanged(this, DISPOSED);
+ }
+
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].dispose();
+ }
+
+ synchronized (this) {
+ m_factory.disposed(this);
+ m_clazz = null;
+ // Do not clean registration map, so injection still works
+ // after disposal for late callbacks.
+ }
+ }
+
+ /**
+ * Sets the state of the component instance.
+ * If the state changes, calls the {@link PrimitiveHandler#stateChanged(int)} method on the attached handlers.
+ * This method has a reentrant mechanism. If in the flow of the first call the method is called another times,
+ * the second call is stored and executed after the first one finished.
+ *
+ * @param state the new state
+ */
+ public void setState(int state) {
+ int originalState = -2;
+ List listeners = null;
+ synchronized (this) {
+ if (m_inTransition) {
+ m_stateQueue.add(new Integer(state));
+ return;
+ }
+
+ if (m_state != state) {
+ m_inTransition = true;
+ originalState = m_state; // Stack confinement.
+ m_state = state;
+ if (m_listeners != null) {
+ listeners = new ArrayList(m_listeners); // Stack confinement.
+ }
+ }
+ }
+
+ // This section can be executed only by one thread at the same time. The m_inTransition pseudo semaphore block access to this section.
+ if (m_inTransition) { // Check that we are really changing.
+ if (state > originalState) {
+ // The state increases (Stopped = > IV, IV => V) => invoke handlers from the higher priority to the lower
+ try {
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].getHandler().stateChanged(state);
+ }
+ } catch (IllegalStateException e) {
+ // When an illegal state exception happens, the instance manager must be stopped immediately.
+ stop();
+ m_logger.log(Logger.ERROR, e.getMessage(), e);
+ return;
+ }
+ } else {
+ // The state decreases (V => IV, IV = > Stopped, Stopped => Disposed)
+ try {
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].getHandler().stateChanged(state);
+ }
+ } catch (IllegalStateException e) {
+ // When an illegal state exception happens, the instance manager must be stopped immediately.
+ stop();
+ m_logger.log(Logger.ERROR, e.getMessage());
+ return;
+ }
+ }
+ }
+
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ ((InstanceStateListener) listeners.get(i)).stateChanged(this, state);
+ }
+ }
+
+ synchronized (this) {
+ m_inTransition = false;
+ if (!m_stateQueue.isEmpty()) {
+ int newState = ((Integer) (m_stateQueue.remove(0))).intValue();
+ setState(newState);
+ }
+ }
+ }
+
+ /**
+ * Gets the actual state of the instance.
+ * Possible values are:
+ * <li>{@link ComponentInstance#INVALID}</li>
+ * <li>{@link ComponentInstance#VALID}</li>
+ * <li>{@link ComponentInstance#DISPOSED}</li>
+ * <li>{@link ComponentInstance#STOPPED}</li>
+ *
+ * @return the actual state of the component instance.
+ * @see org.apache.felix.ipojo.ComponentInstance#getState()
+ */
+ public synchronized int getState() {
+ return m_state;
+ }
+
+ /**
+ * Checks if the instance is started.
+ * An instance is started if the state is either
+ * {@link ComponentInstance#VALID} or {@link ComponentInstance#INVALID}.
+ *
+ * @return <code>true</code> if the instance is started.
+ * @see org.apache.felix.ipojo.ComponentInstance#isStarted()
+ */
+ public synchronized boolean isStarted() {
+ return m_state > STOPPED;
+ }
+
+ /**
+ * Registers an instance state listener.
+ *
+ * @param listener the listener to register.
+ * @see org.apache.felix.ipojo.ComponentInstance#addInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
+ */
+ public synchronized void addInstanceStateListener(InstanceStateListener listener) {
+ if (m_listeners == null) {
+ m_listeners = new ArrayList();
+ }
+ m_listeners.add(listener);
+ }
+
+ /**
+ * Unregisters an instance state listener.
+ *
+ * @param listener the listener to unregister.
+ * @see org.apache.felix.ipojo.ComponentInstance#removeInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
+ */
+ public synchronized void removeInstanceStateListener(InstanceStateListener listener) {
+ if (m_listeners != null) {
+ m_listeners.remove(listener);
+ if (m_listeners.isEmpty()) {
+ m_listeners = null;
+ }
+ }
+ }
+
+ /**
+ * Gets the factory which has created the current instance.
+ *
+ * @return the factory of the component
+ * @see org.apache.felix.ipojo.ComponentInstance#getFactory()
+ */
+ public ComponentFactory getFactory() {
+ return m_factory;
+ }
+
+ /**
+ * Loads the manipulated class.
+ */
+ protected void load() {
+ try {
+ m_clazz = m_factory.loadClass(m_className);
+ } catch (ClassNotFoundException e) {
+ m_logger.log(Logger.ERROR, "[" + m_name + "] Class not found during the loading phase : " + e.getMessage(), e);
+ stop();
+ return;
+ }
+ }
+
+ /**
+ * Gets the object array created by the instance.
+ *
+ * @return the created content objects of the component instance.
+ */
+ public synchronized Object[] getPojoObjects() {
+ if (m_pojoObjects == null) {
+ return null;
+ }
+ return m_pojoObjects.toArray(new Object[m_pojoObjects.size()]);
+ }
+
+ /**
+ * Creates a POJO objects.
+ * This method is not synchronized and does not require any locks.
+ * If a {@link InstanceManager#m_factoryMethod} is specified,
+ * this method called this static method to creates the object.
+ * Otherwise, the methods uses the regular constructor.
+ * All those methods can receive the {@link BundleContext} in
+ * argument.
+ *
+ * @return the created object or <code>null</code> if an error
+ * occurs during the creation.
+ */
+ protected Object createObject() {
+ if (m_clazz == null) {
+ load();
+ }
+
+ // The following code doesn't need to be synchronized as is deal only with immutable fields.
+ Object instance = null;
+ if (m_factoryMethod == null) {
+ // No factory-method, we use the constructor.
+ try {
+ // Try to find the correct constructor.
+ if (m_constructorRegistration != null) {
+ // Initialize the injected values and types
+ // We have the IM first.
+ Object[] values = new Object[m_constructorRegistration.size() + 1];
+ Class[] types = new Class[m_constructorRegistration.size() + 1];
+ values[0] = this;
+ types[0] = InstanceManager.class;
+
+ // Iterate over the constructor injector
+ for (int i = 0; i < m_constructorRegistration.size(); i++) {
+ ConstructorInjector injector = (ConstructorInjector)
+ m_constructorRegistration.get(new Integer(i));
+ Object v = injector.getConstructorParameter(i);
+ if (v != null) {
+ values[i + 1] = v;
+ Class t = injector.getConstructorParameterType(i);
+ if (t == null) {
+ t = v.getClass();
+ }
+ types[i + 1] = t;
+ }
+ }
+ // Find the constructor.
+ Constructor cst = m_clazz.getDeclaredConstructor(types);
+ if (!cst.isAccessible()) {
+ cst.setAccessible(true);
+ }
+ String methodId = MethodMetadata.computeMethodId(cst);
+ onEntry(null, methodId, values);
+ instance = cst.newInstance(values);
+ onExit(instance, methodId, instance);
+ } else {
+ // Old semantic
+ // Try to find if there is a constructor with a bundle context as parameter :
+ try {
+ Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class, BundleContext.class});
+ if (!cst.isAccessible()) {
+ cst.setAccessible(true);
+ }
+ Object[] args = new Object[]{this, m_context};
+ onEntry(null, MethodMetadata.BC_CONSTRUCTOR_ID, new Object[]{m_context});
+ instance = cst.newInstance(args);
+ onExit(instance, MethodMetadata.BC_CONSTRUCTOR_ID, instance);
+ } catch (NoSuchMethodException e) {
+ // Create an instance if no instance are already created with <init>()BundleContext
+ if (instance == null) {
+ Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class});
+ if (!cst.isAccessible()) {
+ cst.setAccessible(true);
+ }
+ Object[] args = new Object[]{this};
+ onEntry(null, MethodMetadata.EMPTY_CONSTRUCTOR_ID, new Object[0]);
+ instance = cst.newInstance(args);
+ onExit(instance, MethodMetadata.EMPTY_CONSTRUCTOR_ID, instance);
+ }
+ }
+ }
+
+ } catch (IllegalAccessException e) {
+ m_logger.log(Logger.ERROR,
+ "[" + m_name + "] createInstance -> The POJO constructor is not accessible : " + e.getMessage(), e);
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
+ } catch (SecurityException e) {
+ m_logger.log(
+ Logger.ERROR,
+ "["
+ + m_name
+ + "] createInstance -> The POJO constructor is not accessible (security reason) : "
+ + e.getMessage(), e
+ );
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
+ } catch (InvocationTargetException e) {
+ m_logger.log(
+ Logger.ERROR,
+ "["
+ + m_name
+ + "] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : "
+ + e.getTargetException().getMessage(), e.getTargetException()
+ );
+ onError(null, m_className, e.getTargetException());
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the POJO constructor has thrown an exception", e.getTargetException());
+ } catch (NoSuchMethodException e) {
+ // Improve the log message because of FELIX-4455, we will see if we get better feedback.
+ m_logger.log(Logger.ERROR,
+ "[" + m_name + "] iPOJO did not find a suitable constructor to create the " +
+ "object: " + e.getMessage(), e);
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the POJO constructor cannot be found", e);
+ } catch (Throwable e) {
+ // Catch every other possible error and runtime exception.
+ m_logger.log(Logger.ERROR,
+ "[" + m_name + "] createInstance -> The POJO constructor invocation failed : " + e.getMessage(), e);
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the POJO constructor invocation has thrown an exception", e);
+ }
+ } else {
+ try {
+ // Build the pojo object with the factory-method.
+ Method factory = null;
+ // Try with the bundle context
+ try {
+ factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[]{BundleContext.class});
+ if (!factory.isAccessible()) {
+ factory.setAccessible(true);
+ }
+ Object[] args = new Object[]{m_context};
+ onEntry(null, m_className, args);
+ instance = factory.invoke(null, new Object[]{m_context});
+ } catch (NoSuchMethodException e1) {
+ // Try without the bundle context
+ try {
+ factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[0]);
+ if (!factory.isAccessible()) {
+ factory.setAccessible(true);
+ }
+ Object[] args = new Object[0];
+ onEntry(null, m_className, args);
+ instance = factory.invoke(null, args);
+ } catch (NoSuchMethodException e2) {
+ // Error : factory-method not found
+ m_logger.log(
+ Logger.ERROR,
+ "["
+ + m_name
+ + "] createInstance -> Cannot invoke the factory-method (method not found) : "
+ + e2.getMessage(), e2
+ );
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found", e2);
+ }
+ }
+
+ // Now call the setInstanceManager method.
+ // Find declaring super class.
+ Class declaringClass = instance.getClass();
+ Method method = null;
+ while (declaringClass != null && method == null) {
+ try {
+ method = declaringClass.getDeclaredMethod("_setInstanceManager",
+ new Class[]{InstanceManager.class});
+ } catch (NoSuchMethodException e) {
+ //Do nothing
+ }
+
+ declaringClass = declaringClass.getSuperclass();
+ }
+
+ if (method == null) {
+ // Error : _setInstanceManager method is missing
+ m_logger
+ .log(
+ Logger.ERROR,
+ "["
+ + m_name
+ + "] createInstance -> Cannot invoke the factory-method (the _setInstanceManager method does not exist"
+ );
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found");
+ }
+
+ if (!method.isAccessible()) {
+ method.setAccessible(true);
+ }
+ method.invoke(instance, new Object[]{this});
+ onExit(null, m_className, instance);
+
+ } catch (InvocationTargetException e) {
+ // Error : invocation failed
+ m_logger.log(Logger.ERROR,
+ "[" + m_name + "] createInstance -> The factory-method throws an exception : " + e.getTargetException(), e.getTargetException());
+ onError(null, m_className, e.getTargetException());
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the factory-method has thrown an exception", e.getTargetException());
+ } catch (Throwable e) {
+ // Catch every other possible error and runtime exception.
+ m_logger.log(Logger.ERROR,
+ "[" + m_name + "] createInstance -> The factory-method invocation failed : " + e.getMessage(), e);
+ stop();
+ throw new RuntimeException("Cannot create a POJO instance, the factory-method invocation has thrown an exception", e);
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * Creates an instance of the content.
+ * This method needs to be called once only for singleton provided service.
+ * This methods call the {@link InstanceManager#createObject()} method, and adds
+ * the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
+ * it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
+ * handlers.
+ *
+ * @return a new instance or <code>null</code> if an error occurs during the
+ * creation.
+ */
+ public Object createPojoObject() {
+ Object instance = createObject();
+
+ // Add the new instance in the instance list.
+ synchronized (this) {
+ if (m_pojoObjects == null) {
+ m_pojoObjects = new ArrayList(1);
+ }
+ m_pojoObjects.add(instance);
+ }
+ // Call createInstance on Handlers :
+ for (int i = 0; i < m_handlers.length; i++) {
+ // This methods must be call without the monitor lock.
+ ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(instance);
+ }
+
+ return instance;
+ }
+
+ /**
+ * Deletes a POJO object.
+ *
+ * @param pojo the pojo to remove from the list of created pojos.
+ */
+ public synchronized void deletePojoObject(Object pojo) {
+ if (m_pojoObjects != null) {
+ m_pojoObjects.remove(pojo);
+ }
+ }
+
+ /**
+ * Gets the first object created by the instance.
+ * If no object created, creates and returns a POJO object.
+ * This methods call the {@link InstanceManager#createObject()} method, and adds
+ * the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
+ * it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
+ * handlers.
+ * <br/>
+ * <p>
+ * <b>TODO</b> this method has a potential race condition if two threads require a pojo
+ * object at the same time. Only one object will be created, but the second thread
+ * can receive the created object before the {@link PrimitiveHandler#onCreation(Object)}
+ * calls.
+ * </p>
+ *
+ * @return the pojo object of the component instance to use for singleton component
+ */
+ 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;
+ }
+ }
+
+ // 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:
+ // a second thread get the created object before the first one (which created the object),
+ // call onCreation.
+
+ return pojo;
+ }
+
+ /**
+ * Gets the manipulated class.
+ * The method does not need to be synchronized.
+ * Reassigning the internal class will use the same class object.
+ *
+ * @return the manipulated class
+ */
+ public Class getClazz() {
+ if (m_clazz == null) {
+ load();
+ }
+ return m_clazz;
+ }
+
+ /**
+ * Configures an injected object in this container.
+ */
+ private void managedInjectedObject() {
+ Object obj = m_pojoObjects.get(0); // Get first object.
+
+ if (!(obj instanceof Pojo)) {
+ // Error, the injected object is not a POJO.
+ throw new RuntimeException("The injected object in " + m_name + " is not a POJO");
+ }
+
+ load(); // Load the class.
+
+ if (!m_clazz.isInstance(obj)) {
+ throw new RuntimeException("The injected object in " + m_name + " is not an instance of " + m_className);
+ }
+
+ // Call _setInstanceManager
+ try {
+ Method setIM = m_clazz.getDeclaredMethod("_setInstanceManager", new Class[]{this.getClass()});
+ setIM.setAccessible(true); // Necessary as the method is private
+ setIM.invoke(obj, new Object[]{this});
+ } catch (Exception e) {
+ // If anything wrong happened...
+ throw new RuntimeException("Cannot attach the injected object with the container of " + m_name, e);
+ }
+
+ // Call createInstance on Handlers :
+ for (int i = 0; i < m_handlers.length; i++) {
+ // This methods must be call without the monitor lock.
+ ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(obj);
+ }
+
+
+ }
+
+ /**
+ * Registers an handler.
+ * This methods is called by handler wanting to monitor
+ * fields and/or methods of the implementation class.
+ *
+ * @param handler the handler to register
+ * @param fields the field metadata list
+ * @param methods the method metadata list
+ * @deprecated use {@link InstanceManager#register(FieldMetadata, FieldInterceptor)}
+ * and {@link InstanceManager#register(MethodMetadata, MethodInterceptor)} instead.
+ */
+ public void register(PrimitiveHandler handler, FieldMetadata[] fields, MethodMetadata[] methods) {
+ for (int i = 0; fields != null && i < fields.length; i++) {
+ register(fields[i], handler);
+ }
+ for (int i = 0; methods != null && i < methods.length; i++) {
+ register(methods[i], handler);
+ }
+
+ }
+
+ /**
+ * Registers a field interceptor.
+ * A field interceptor will be notified of field access of the
+ * implementation class. Note that handlers are field interceptors.
+ *
+ * @param field the field to monitor
+ * @param interceptor the field interceptor object
+ */
+ public void register(FieldMetadata field, FieldInterceptor interceptor) {
+ if (m_fieldRegistration == null) {
+ m_fieldRegistration = new HashMap();
+ m_fieldRegistration.put(field.getFieldName(), new FieldInterceptor[]{interceptor});
+ } else {
+ FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration.get(field.getFieldName());
+ if (list == null) {
+ m_fieldRegistration.put(field.getFieldName(), new FieldInterceptor[]{interceptor});
+ } else {
+ for (int j = 0; j < list.length; j++) {
+ if (list[j] == interceptor) {
+ return;
+ }
+ }
+ FieldInterceptor[] newList = new FieldInterceptor[list.length + 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ newList[list.length] = interceptor;
+ m_fieldRegistration.put(field.getFieldName(), newList);
+ }
+ }
+ }
+
+ /**
+ * Registers a method interceptor.
+ * A method interceptor will be notified of method entries, exits
+ * and errors. Note that handlers are method interceptors.
+ *
+ * @param method the field to monitor
+ * @param interceptor the field interceptor object
+ */
+ public void register(MethodMetadata method, MethodInterceptor interceptor) {
+ if (m_methodRegistration == null) {
+ m_methodRegistration = new HashMap();
+ m_methodRegistration.put(method.getMethodIdentifier(), new MethodInterceptor[]{interceptor});
+ } else {
+ MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(method.getMethodIdentifier());
+ if (list == null) {
+ m_methodRegistration.put(method.getMethodIdentifier(), new MethodInterceptor[]{interceptor});
+ } else {
+ for (int j = 0; j < list.length; j++) {
+ if (list[j] == interceptor) {
+ return;
+ }
+ }
+ MethodInterceptor[] newList = new MethodInterceptor[list.length + 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ newList[list.length] = interceptor;
+ m_methodRegistration.put(method.getMethodIdentifier(), newList);
+ }
+ }
+ }
+
+ /**
+ * Registers a method interceptor on a methods from an inner class.
+ * A method interceptor will be notified of method entries, exits
+ * and errors. Note that handlers are method interceptors.
+ *
+ * @param method the field to monitor
+ * @param innerClass the inner class name
+ * @param interceptor the field interceptor object
+ */
+ public void register(MethodMetadata method, String innerClass, MethodInterceptor interceptor) {
+ if (m_methodRegistration == null) {
+ m_methodRegistration = new HashMap();
+ m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(),
+ new MethodInterceptor[]{interceptor});
+ } else {
+ MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(method.getMethodIdentifier());
+ if (list == null) {
+ m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(),
+ new MethodInterceptor[]{interceptor});
+ } else {
+ for (int j = 0; j < list.length; j++) {
+ if (list[j] == interceptor) {
+ return;
+ }
+ }
+ MethodInterceptor[] newList = new MethodInterceptor[list.length + 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ newList[list.length] = interceptor;
+ m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(), newList);
+ }
+ }
+ }
+
+ /**
+ * Registers a constructor injector.
+ * The constructor injector will be called when a pojo object is going to be
+ * created.
+ *
+ * @param index the index of the parameter. Only one injector per index can
+ * be registered.
+ * @param injector the injector object.
+ * @throws ConfigurationException if the given index is already injected by another
+ * injector
+ */
+ public void register(int index, ConstructorInjector injector) throws ConfigurationException {
+ if (m_constructorRegistration == null) {
+ m_constructorRegistration = new HashMap();
+ }
+ if (!m_constructorRegistration.containsKey(index)) {
+ m_constructorRegistration.put(index, injector);
+ } else {
+ throw new ConfigurationException("Another constructor injector " +
+ "manages the parameter " + index + " : " + m_constructorRegistration.get(index) + ", so cannot " +
+ "register " + injector);
+ }
+ }
+
+ /**
+ * This method is called by the manipulated class each time that a GETFIELD instruction is executed.
+ * The method asks to each attached handler monitoring this field which value need
+ * to be injected (i.e. returned) by invoking the {@link PrimitiveHandler#onGet(Object, String, Object)}
+ * method. If the field value changes, this method call the {@link PrimitiveHandler#onSet(Object, String, Object)}
+ * method on each field interceptor monitoring the field in order to advertize the new value.
+ *
+ * @param pojo the pojo object on which the field was get
+ * @param fieldName the field name on which the GETFIELD instruction is called
+ * @return the value decided by the last asked handler (throws a warning if two fields decide two different values)
+ */
+ public Object onGet(Object pojo, String fieldName) {
+ Object initialValue = null;
+ synchronized (this) { // Stack confinement.
+ initialValue = m_fields.get(fieldName);
+ }
+ Object result = initialValue;
+ boolean hasChanged = false;
+ // Get the list of registered handlers
+ FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration.get(fieldName); // Immutable list.
+ for (int i = 0; list != null && i < list.length; i++) {
+ // Call onGet outside of a synchronized block.
+ Object handlerResult = list[i].onGet(pojo, fieldName, initialValue);
+ if (handlerResult == initialValue) {
+ continue; // Non-binding case (default implementation).
+ } else {
+ if (result != initialValue) {
+ //TODO analyze impact of removing conflict detection
+ if ((handlerResult != null && !handlerResult.equals(result)) || (result != null && handlerResult == null)) {
+ m_logger.log(
+ Logger.WARNING,
+ "A conflict was detected on the injection of "
+ + fieldName
+ );
+ }
+ }
+ result = handlerResult;
+ hasChanged = true;
+ }
+ }
+ if (hasChanged) {
+ // A change occurs => notify the change
+ //TODO consider just changing the reference, however multiple thread can be an issue
+ synchronized (this) {
+ m_fields.put(fieldName, result);
+ }
+ // Call onset outside of a synchronized block.
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onSet(pojo, fieldName, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Dispatches entry method events on registered method interceptors.
+ * This method calls the {@link MethodInterceptor#onEntry(Object, java.lang.reflect.Member, Object[])}
+ * methods on method interceptors monitoring the method.
+ *
+ * @param pojo the pojo object on which method is invoked.
+ * @param methodId the method id used to compute the {@link Method} object.
+ * @param args the argument array
+ */
+ public void onEntry(Object pojo, String methodId, Object[] args) {
+ if (m_methodRegistration == null) { // Immutable field.
+ return;
+ }
+
+ MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
+ Member method = getMethodById(methodId);
+ // We can't find the member object of anonymous methods.
+
+ // In case of a constructor, the method is null, and the list is null too.
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onEntry(pojo, method, args); // Outside a synchronized block.
+ }
+ }
+
+ /**
+ * Dispatches exit method events on registered method interceptors.
+ * The given returned object is an instance of {@link Exception} if the method thrown an
+ * exception. If the given object is <code>null</code>, either the method returns <code>void</code>,
+ * or the method has returned <code>null</code>
+ * This method calls the {@link MethodInterceptor#onExit(Object, java.lang.reflect.Member, Object)} and the
+ * {@link MethodInterceptor#onFinally(Object, java.lang.reflect.Member)} methods on method interceptors
+ * monitoring the method.
+ *
+ * @param pojo the pojo object on which method was invoked.
+ * @param methodId the method id used to compute the {@link Method} object.
+ * @param result the returned object.
+ */
+ public void onExit(Object pojo, String methodId, Object result) {
+ if (m_methodRegistration == null) {
+ return;
+ }
+ MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
+ Member method = getMethodById(methodId);
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onExit(pojo, method, result);
+ }
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onFinally(pojo, method);
+ }
+ }
+
+ /**
+ * Dispatches error method events on registered method interceptors.
+ * or the method has returned <code>null</code>
+ * This method calls the {@link MethodInterceptor#onError(Object, java.lang.reflect.Member, Throwable)} and the
+ * {@link MethodInterceptor#onFinally(Object, java.lang.reflect.Member)} methods on method interceptors monitoring
+ * the method.
+ *
+ * @param pojo the pojo object on which the method was invoked
+ * @param methodId the method id used to compute the {@link Method} object.
+ * @param error the Throwable object.
+ */
+ public void onError(Object pojo, String methodId, Throwable error) {
+ if (m_methodRegistration == null) {
+ return;
+ }
+ MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
+ Member method = getMethodById(methodId);
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onError(pojo, method, error);
+ }
+ for (int i = 0; list != null && i < list.length; i++) {
+ list[i].onFinally(pojo, method);
+ }
+ }
+
+ /**
+ * Computes the {@link Method} object from the given id.
+ * Once computes, a map is used as a cache to avoid to recompute for
+ * the same id.
+ *
+ * @param methodId the method id
+ * @return the method object or <code>null</code> if the method cannot be found.
+ */
+ private Member getMethodById(String methodId) {
+ // Used a synchronized map.
+ Member member = (Member) m_methods.get(methodId);
+ if (!m_methods.containsKey(methodId) && m_clazz != null) {
+ // Is it a inner class method
+ if (methodId.contains("___")) { // Mark to detect a inner class method.
+ String[] split = methodId.split("___");
+ if (split.length != 2) {
+ m_logger.log(Logger.INFO, "A methodID cannot be associated with a method from the POJO class: " + methodId);
+ return null;
+ } else {
+ String innerClassName = split[0];
+ methodId = split[1];
+
+ // We can't find the member objects from anonymous methods, identified by their numeric name
+ // Just escaping in this case.
+ if (innerClassName.matches("-?\\d+")) {
+ m_methods.put(methodId, null);
+ return null;
+ }
+
+ for (Class c : m_clazz.getDeclaredClasses()) {
+ if (innerClassName.equals(c.getSimpleName())) {
+ Method[] mets = c.getDeclaredMethods();
+ for (Method met : mets) {
+ if (MethodMetadata.computeMethodId(met).equals(methodId)) {
+ // Store the new methodId
+ m_methods.put(methodId, met);
+ return met;
+ }
+ }
+ }
+ m_logger.log(Logger.INFO, "Cannot find the member associated to " + methodId + " - reason: " +
+ "cannot find the class " + innerClassName + " declared in " + m_clazz.getName());
+ }
+ }
+ }
+
+
+ // First try on methods.
+ Method[] mets = m_clazz.getDeclaredMethods();
+ for (int i = 0; i < mets.length; i++) {
+ if (MethodMetadata.computeMethodId(mets[i]).equals(methodId)) {
+ // Store the new methodId
+ m_methods.put(methodId, mets[i]);
+ return mets[i];
+ }
+ }
+
+ // If not found, it is a constructor, return the constructor object in this case.
+ if (methodId.startsWith(MethodMetadata.CONSTRUCTOR_PREFIX)) {
+ Constructor[] constructors = m_clazz.getDeclaredConstructors();
+ for (int i = 0; i < constructors.length; i++) {
+ // Check if the constructor was not already computed. If not, compute the Id and check.
+ if (MethodMetadata.computeMethodId(constructors[i]).equals(methodId)) {
+ // Store the new methodId
+ m_methods.put(methodId, constructors[i]);
+ return constructors[i];
+ }
+ }
+ }
+
+ // Should not happen
+ m_logger.log(Logger.INFO, "A methodID cannot be associated with a method from the POJO class: " + methodId);
+ return null;
+ } else {
+ return member;
+ }
+ }
+
+ /**
+ * This method is called by the manipulated class each time that a PUTFIELD instruction is executed.
+ * The method calls the {@link PrimitiveHandler#onSet(Object, String, Object)} method on each field
+ * interceptors monitoring this field.
+ * This method can be invoked with a <code>null</code> pojo argument when the changes comes from another
+ * handler.
+ *
+ * @param pojo the pojo object on which the field was set
+ * @param fieldName the field name on which the PUTFIELD instruction is called
+ * @param objectValue the new value of the field
+ */
+ public void onSet(final Object pojo, final String fieldName, final Object objectValue) {
+ synchronized (this) {
+ // First, store the new value.
+ // This must be done in a synchronized block to avoid
+ // concurrent modification
+ m_fields.put(fieldName, objectValue);
+ }
+ // The registrations cannot be modified, so we can directly access
+ // the interceptor list.
+ FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration
+ .get(fieldName);
+ for (int i = 0; list != null && i < list.length; i++) {
+ // The callback must be call outside the synchronization block.
+ list[i].onSet(pojo, fieldName, objectValue);
+ }
+ }
+
+
+ /**
+ * Gets the bundle context used by this component instance.
+ *
+ * @return the context of the component.
+ * @see org.apache.felix.ipojo.ComponentInstance#getContext()
+ */
+ public BundleContext getContext() {
+ return m_context; // Immutable
+ }
+
+ /**
+ * Gets the global bundle context. This is the bundle context
+ * of the bundle declaring the component type.
+ *
+ * @return the bundle context of the bundle declaring the component
+ * type.
+ */
+ public BundleContext getGlobalContext() {
+ return ((IPojoContext) m_context).getGlobalContext(); // Immutable
+ }
+
+
+ /**
+ * Gets the local service context. This service context gives
+ * access to the 'local' service registry (the composite one).
+ * If the instance lives in the global (i.e. OSGi) context,
+ * this method returns <code>null</code>
+ *
+ * @return the local service context or <code>null</code> if the
+ * instance doesn't live in a composite.
+ */
+ public ServiceContext getLocalServiceContext() {
+ return ((IPojoContext) m_context).getServiceContext(); // Immutable
+ }
+
+ /**
+ * Gets the instance name.
+ *
+ * @return the instance name.
+ * @see org.apache.felix.ipojo.ComponentInstance#getInstanceName()
+ */
+ public String getInstanceName() {
+ return m_name; // Immutable
+ }
+
+ /**
+ * Reconfigures the current instance.
+ * Reconfiguring an instance means re-injecting a new
+ * instance configuration. Some properties are immutable
+ * such as the instance name.
+ * This methods calls the {@link PrimitiveHandler#reconfigure(Dictionary)}
+ * methods on each attached handler, and then recompute the instance
+ * state. Note that the reconfiguration process does not deactivate the
+ * instance.
+ *
+ * @param configuration the new configuration to push
+ * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary configuration) {
+ m_logger.log(Logger.INFO, "Reconfiguring " + getInstanceName());
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].getHandler().reconfigure(configuration);
+ }
+ // We synchronized the state computation.
+ synchronized (this) {
+ if (m_state == STOPPED) {
+ m_logger.log(Logger.INFO, "Instance stopped during reconfiguration - Try to restart");
+ start();
+ } else if (m_state == INVALID) {
+ m_logger.log(Logger.INFO, "Instance invalid during reconfiguration - Recompute state");
+ // Try to revalidate the instance after reconfiguration
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getState() != VALID) {
+ return;
+ }
+ }
+ setState(VALID);
+ }
+ }
+ }
+
+ /**
+ * Gets the implementation class of the component type.
+ * This method does not need to be synchronized as the
+ * class name is constant once set.
+ *
+ * @return the class name of the component implementation.
+ */
+ public String getClassName() {
+ return m_className;
+ }
+
+ /**
+ * State Change listener callback.
+ * This method is called every time that a plugged handler becomes valid or invalid.
+ * This method computes the new instance state and applies it (by calling the
+ * {@link InstanceManager#setState(int)} method.
+ *
+ * @param instance the handler becoming valid or invalid
+ * @param newState the new state of the handler
+ * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
+ */
+ public void stateChanged(ComponentInstance instance, int newState) {
+ int state;
+ synchronized (this) {
+ if (m_state <= STOPPED) {
+ return;
+ } else {
+ state = m_state; // Stack confinement
+ }
+ }
+
+ // Update the component state if necessary
+ if (newState == INVALID && state == VALID) {
+ // Need to update the state to UNRESOLVED
+ setState(INVALID);
+ return;
+ }
+ if (newState == VALID && state == INVALID) {
+ // An handler becomes valid => check if all handlers are valid
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getState() != VALID) {
+ return;
+ }
+ }
+ setState(VALID);
+ return;
+ }
+ }
+
+ /**
+ * Gets the list of registered fields (containing field names).
+ * This method is invoked by the POJO itself during
+ * its initialization.
+ *
+ * @return the set of registered fields.
+ */
+ public Set getRegistredFields() {
+ // IMPORTANT - method used by the manipulator
+ if (m_fieldRegistration == null) {
+ return null;
+ }
+ return m_fieldRegistration.keySet();
+ }
+
+ /**
+ * Gets the list of registered methods (containing method ids).
+ * This method is invoked by the POJO itself during its
+ * initialization.
+ *
+ * @return the set of registered methods.
+ */
+ public Set getRegistredMethods() {
+ // IMPORTANT - method used by the manipulator
+ if (m_methodRegistration == null) {
+ return null;
+ } else {
+ return m_methodRegistration.keySet();
+ }
+ }
+
+ /**
+ * Gets the bundle context of the instance, i.e. the bundle context of the bundle having declared this instance.
+ *
+ * @return the bundle context of the instance.
+ * @since 1.11.2
+ */
+ public BundleContext getInstanceContext() {
+ return m_instanceContext;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceStateListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceStateListener.java
new file mode 100644
index 0000000..d6ec53a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceStateListener.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * This class defines instance state listeners.
+ * An instance state listener is notified of instance state changes. It needs to be
+ * registered on the instance by invoking the ({@link ComponentInstance#addInstanceStateListener(InstanceStateListener)}
+ * method. Once registered, the listener can track instance state changes.
+ * Received states are:
+ * <li>{@link ComponentInstance#VALID}</li>
+ * <li>{@link ComponentInstance#INVALID}</li>
+ * <li>{@link ComponentInstance#STOPPED}</li>
+ * <li>{@link ComponentInstance#DISPOSED}</li>
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface InstanceStateListener {
+
+ /**
+ * State change listener callback method.
+ * Every time that a monitored instance's state changes,
+ * this method is called with the instance and the new state.
+ * @param instance the changing instance
+ * @param newState the new instance state
+ */
+ void stateChanged(ComponentInstance instance, int newState);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java
new file mode 100644
index 0000000..15560fe
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MethodInterceptor.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+* Method interceptor.
+* A class implementing this interface is able to be notified of method invocations (
+* i.e. entries, exits, and errors).
+* The listener needs to be register on the instance manager with the
+* {@link InstanceManager#register(org.apache.felix.ipojo.parser.MethodMetadata, MethodInterceptor)}
+* method.
+* Events are sent before the method entry (onEntry), after the method returns (onExit),
+* when an error is thrown by the method (onError), and before the after either a returns or an error (onFinally).
+*
+* Instead of a {@link Method} object, the callbacks received a {@link Member} object which can be either a {@link Method}
+* or a {@link Constructor}.
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+public interface MethodInterceptor {
+
+ /**
+ * This method is called when a thread enters in a method.
+ * The given argument array is created from the method argument.
+ * @param pojo the pojo on which the method is called.
+ * @param method the invoked method.
+ * @param args the arguments array.
+ */
+ void onEntry(Object pojo, Member method, Object[] args);
+
+ /**
+ * This method is called when the execution exits a method :
+ * before a <code>return</code>.
+ * If the given returned object is <code>null</code>, either the method is
+ * <code>void</code>, or it returns <code>null</code>.
+ * This method must not modify the returned object.
+ * @param pojo the pojo on which the method exits.
+ * @param method the exiting method.
+ * @param returnedObj the the returned object (boxed for primitive type)
+ */
+ void onExit(Object pojo, Member method, Object returnedObj);
+
+ /**
+ * This method is called when the execution throws an exception in the given
+ * method.
+ * @param pojo the pojo on which the method was accessed.
+ * @param method the invoked method.
+ * @param throwable the thrown exception
+ */
+ void onError(Object pojo, Member method, Throwable throwable);
+
+ /**
+ * This method is called when the execution of a method is going to terminate :
+ * just before to throw an exception or before to return.
+ * (onError or onExit was already called).
+ * @param pojo the pojo on which the method was accessed.
+ * @param method the invoked method.
+ */
+ void onFinally(Object pojo, Member method);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MissingHandlerException.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MissingHandlerException.java
new file mode 100644
index 0000000..9bc4efb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/MissingHandlerException.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import java.util.List;
+
+/**
+ * Missing Handler Exception.
+ * This exception occurs when an handler factory is missing to create an instance.
+ * In fact, when a required handler factory is not avialable or valid, the {@link Handler}
+ * object cannot be created, and so the instance container cannot be completed.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MissingHandlerException extends Exception {
+
+ /**
+ * Serialization Id.
+ */
+ private static final long serialVersionUID = 5047792897590881478L;
+
+ /**
+ * The message.
+ */
+ private String m_message;
+
+ /**
+ * Creates a MissingHandlerException.
+ * This methods computes the message from
+ * the given list.
+ * @param missing the list of missing handlers.
+ */
+ public MissingHandlerException(List missing) {
+ super();
+ m_message = "Missing handlers : ";
+ for (int i = 0; i < missing.size(); i++) {
+ m_message += (String) missing.get(i) + " ";
+ }
+ }
+
+ /**
+ * Gets the error message.
+ * @return the error message
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ return m_message;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Nullable.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Nullable.java
new file mode 100644
index 0000000..075f4c7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Nullable.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * A Nullable object must implement this interface.
+ * This allows to the code checking if the injected object is
+ * a Nullable object or not such as in:<br/>
+ * <code>if(foo instanceof Nullable){...}</code>
+ * <br/>
+ * This interface does not define any methods. Nullable objects owns
+ * the same methods than the 'real' object.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Nullable {
+ // Nothing
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Pojo.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Pojo.java
new file mode 100644
index 0000000..8bc7779
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/Pojo.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * Interface implemented by each manipulated class.
+ * This interface allows getting the component instance from the object.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Pojo {
+
+ /**
+ * Gets the instance container which creates the current object.
+ * @return the component instance which creates this object.
+ */
+ ComponentInstance getComponentInstance();
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PolicyServiceContext.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PolicyServiceContext.java
new file mode 100644
index 0000000..1f23af8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PolicyServiceContext.java
@@ -0,0 +1,498 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * The policy service context is a service context aiming to resolve service dependencies
+ * inside different service context according to a policy.
+ * So, the policy service context behavior follows one of the three following policy:
+ * <li> Local : services are only resolved in the local service context.</li>
+ * <li> Global : services are only resolved in the global context (hte OSGi one)</li>
+ * <li> Local and Global : services are resolved inside the local context and inside
+ * the global context</li>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PolicyServiceContext implements ServiceContext {
+
+ /**
+ * Resolving policy, resolves services only in the composite
+ * context (local).
+ * This policy is the default one for services inherited from
+ * service-level dependencies.
+ */
+ public static final int LOCAL = 0;
+
+ /**
+ * Resolving policy, resolves services only in the composite
+ * (local) and in the global context.
+ * This policy is the default one for implementation dependency.
+ */
+ public static final int LOCAL_AND_GLOBAL = 1;
+
+ /**
+ * Resolving policy, resolves services inside the global context
+ * only.
+ */
+ public static final int GLOBAL = 2;
+
+ /**
+ * The global service registry.
+ * Targets the OSGi service registry.
+ */
+ public BundleContext m_global;
+
+ /**
+ * The local (Composite) Service Registry.
+ */
+ public ServiceContext m_local;
+
+ /**
+ * The resolving policy to use to resolve
+ * dependencies.
+ */
+ private int m_policy = LOCAL_AND_GLOBAL;
+
+
+ /**
+ * Creates a PolicyServiceContext.
+ * If the local context is null, sets the policy to
+ * {@link PolicyServiceContext#GLOBAL}, else use the
+ * given policy.
+ * @param global the global bundle context
+ * @param local the parent (local) service context
+ * @param policy the resolution policy
+ */
+ public PolicyServiceContext(BundleContext global, ServiceContext local, int policy) {
+ m_global = global;
+ m_local = local;
+ if (m_local == null) {
+ m_policy = GLOBAL;
+ } else {
+ m_policy = policy;
+ }
+ }
+
+ /**
+ * Adds a service listener according to the policy.
+ * Be aware, that the listener can be registered both in the local and in the global context
+ * if the {@link PolicyServiceContext#LOCAL_AND_GLOBAL} is used.
+ * @param listener the listener to add
+ * @param filter the LDAP filter
+ * @throws InvalidSyntaxException if the filter is malformed.
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String)
+ */
+ public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException {
+ if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_local.addServiceListener(listener, filter);
+ }
+ if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_global.addServiceListener(listener, filter);
+ }
+
+ }
+
+ /**
+ * Adds a service listener according to the policy.
+ * Be aware, that the listener can be registered both in the local and in the global context
+ * if the {@link PolicyServiceContext#LOCAL_AND_GLOBAL} is used.
+ * @param listener the listener to add
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void addServiceListener(ServiceListener listener) {
+ if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_local.addServiceListener(listener);
+ }
+ if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_global.addServiceListener(listener);
+ }
+ }
+
+ /**
+ * Gets all service references.
+ * These references are found inside the local registry, global registry or both according to the policy.
+ * The returned array can contain service references from both context.
+ * @param clazz the required service specification.
+ * @param filter the LDAP filter
+ * @return the array of service reference, <code>null</code> if no service available
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.apache.felix.ipojo.ServiceContext#getAllServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getAllServiceReferences(String clazz,
+ String filter) throws InvalidSyntaxException {
+ switch (m_policy) {
+ case LOCAL:
+ return m_local.getAllServiceReferences(clazz, filter);
+ case GLOBAL:
+ return m_global.getAllServiceReferences(clazz, filter);
+ case LOCAL_AND_GLOBAL:
+ ServiceReference[] refLocal = m_local.getAllServiceReferences(clazz, filter);
+ ServiceReference[] refGlobal = m_global.getAllServiceReferences(clazz, filter);
+ return computeServiceReferencesFromBoth(refLocal, refGlobal);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Gets the service object for the given references.
+ * The service is get inside the context according to the policy.
+ * @param ref the service reference
+ * @return the service object
+ * @see org.apache.felix.ipojo.ServiceContext#getService(org.osgi.framework.ServiceReference)
+ */
+ public Object getService(ServiceReference ref) {
+ if (ref instanceof TransformedServiceReference) {
+ ref = ((TransformedServiceReference) ref).getWrappedReference();
+ }
+ switch(m_policy) { // NOPMD No break needed as we return in each branch.
+ case LOCAL:
+ // The reference comes from the local scope
+ return m_local.getService(ref);
+ case GLOBAL:
+ // The reference comes from the global registry
+ return m_global.getService(ref);
+ case LOCAL_AND_GLOBAL:
+ if (ref instanceof org.apache.felix.ipojo.context.ServiceReferenceImpl) {
+ return m_local.getService(ref);
+ } else {
+ return m_global.getService(ref);
+ }
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Gets a service reference for the required service specification.
+ * The service is looked inside the context according to the policy.
+ * @param clazz the required service specification
+ * @return a service reference or <code>null</code> if no matching service available
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String)
+ */
+ public ServiceReference getServiceReference(String clazz) {
+ switch (m_policy) { // NOPMD No break needed as we return in each branch.
+ case LOCAL:
+ return m_local.getServiceReference(clazz);
+ case GLOBAL:
+ return m_global.getServiceReference(clazz);
+ case LOCAL_AND_GLOBAL:
+ ServiceReference refLocal = m_local.getServiceReference(clazz);
+ if (refLocal == null) {
+ return m_global.getServiceReference(clazz);
+ } else {
+ return refLocal;
+ }
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Gets a service reference.
+ * This method is delegated on PolicyServiceContext#getServiceReference(String)
+ * @param sClass the service interface class
+ * @param <S> the service interface class
+ * @return the service reference of <code>null</code> if not found
+ * @see PolicyServiceContext#getServiceReference(String)
+ */
+ public <S> ServiceReference<S> getServiceReference(Class<S> sClass) {
+ return (ServiceReference<S>) getServiceReference(sClass.getName());
+ }
+
+ /**
+ * Gets a collection of service references
+ * @param clazz the service interface class
+ * @param filter the filter
+ * @param <S> the service interface class
+ * @return the set of service reference
+ * @throws InvalidSyntaxException the filter is invalid
+ * @see PolicyServiceContext#getServiceReferences(String, String)
+ */
+ public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) throws InvalidSyntaxException {
+ ServiceReference<S>[] refs =
+ (ServiceReference<S>[]) getServiceReferences(clazz.getName(), filter);
+ return (refs == null)
+ ? Collections.EMPTY_LIST
+ : (Collection<ServiceReference<S>>) Arrays.asList(refs);
+ }
+
+ /**
+ * Get a service reference for the required service specification.
+ * The services are looked inside the context according to the policy.
+ * @param clazz the required service specification
+ * @param filter the LDAP filter
+ * @return a service reference array or <code>null</code> if not consistent service available
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String)
+ */
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ switch (m_policy) {
+ case LOCAL:
+ return m_local.getServiceReferences(clazz, filter);
+ case GLOBAL:
+ return m_global.getServiceReferences(clazz, filter);
+ case LOCAL_AND_GLOBAL:
+ ServiceReference[] refLocal = m_local.getServiceReferences(clazz, filter);
+ ServiceReference[] refGlobal = m_global.getServiceReferences(clazz, filter);
+ return computeServiceReferencesFromBoth(refLocal, refGlobal);
+ default:
+ return null;
+ }
+
+ }
+
+ /**
+ * Computes the service reference array from the two given set of service references
+ * according to the policy.
+ * @param refLocal the set of local references
+ * @param refGlobal the set of global references
+ * @return the set of service references
+ */
+ private ServiceReference[] computeServiceReferencesFromBoth(ServiceReference[] refLocal, ServiceReference[] refGlobal) {
+ if (refLocal == null) {
+ return refGlobal; // If refGlobal is null, return null, else return refGlobal
+ } else if (refGlobal == null) { // refLocal != null && refGlobal == null
+ return refLocal;
+ } else { // Both refGlobal and refLocal are not null
+ ServiceReference[] refs = new ServiceReference[refLocal.length + refGlobal.length];
+ System.arraycopy(refLocal, 0, refs, 0, refLocal.length);
+ System.arraycopy(refGlobal, 0, refs, refLocal.length, refGlobal.length);
+ return refs;
+ }
+ }
+
+ /**
+ * This method is not supported.
+ * This context can only be used to resolve service dependencies.
+ * @param clazzes the specifications
+ * @param service the service object
+ * @param properties the service properties
+ * @return the service registration object
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) {
+ throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services");
+ }
+
+ /**
+ * This method is not supported.
+ * This context can only be used to resolve service dependencies.
+ * @param clazz the specification
+ * @param service the service object
+ * @param properties the service properties to publish
+ * @return the service registration object
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String clazz, Object service, Dictionary properties) {
+ throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services");
+ }
+
+ /**
+ * Removes a service listener.
+ * @param listener the service listener to remove
+ * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void removeServiceListener(ServiceListener listener) {
+ if (m_policy == LOCAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_local.removeServiceListener(listener);
+ }
+ if (m_policy == GLOBAL || m_policy == LOCAL_AND_GLOBAL) {
+ m_global.removeServiceListener(listener);
+ }
+ }
+
+ /**
+ * Ungets the service reference.
+ * @param reference the service reference to unget.
+ * @return <code>true</code> if the service release if the reference is no more used.
+ * @see org.apache.felix.ipojo.ServiceContext#ungetService(org.osgi.framework.ServiceReference)
+ */
+ public boolean ungetService(ServiceReference reference) {
+ if (reference instanceof org.apache.felix.ipojo.context.ServiceReferenceImpl) {
+ return m_local.ungetService(reference);
+ } else {
+ return m_global.ungetService(reference);
+ }
+ }
+
+ /**
+ * Adds a bundle listener.
+ * Delegate on the global bundle context.
+ * @param arg0 : bundle listener to add
+ * @see org.osgi.framework.BundleContext#addBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void addBundleListener(BundleListener arg0) {
+ m_global.addBundleListener(arg0);
+ }
+
+ /**
+ * Adds a framework listener.
+ * Delegates on the global bundle context.
+ * @param arg0 : framework listener to add.
+ * @see org.osgi.framework.BundleContext#addFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void addFrameworkListener(FrameworkListener arg0) {
+ m_global.addFrameworkListener(arg0);
+ }
+
+ /**
+ * Creates a LDAP filter.
+ * @param arg0 the String-form of the filter
+ * @return the created filter object
+ * @throws InvalidSyntaxException if the given argument is not a valid against the LDAP grammar.
+ * @see org.osgi.framework.BundleContext#createFilter(java.lang.String)
+ */
+ public Filter createFilter(String arg0) throws InvalidSyntaxException {
+ return m_global.createFilter(arg0);
+ }
+
+ /**
+ * Gets a bundle by name
+ * @param s the name
+ * @return the matching bundle or <code>null</code> if not found
+ */
+ public Bundle getBundle(String s) {
+ return m_global.getBundle(s);
+ }
+
+ /**
+ * Gets the current bundle.
+ * @return the current bundle
+ * @see org.osgi.framework.BundleContext#getBundle()
+ */
+ public Bundle getBundle() {
+ return m_global.getBundle();
+ }
+
+ /**
+ * Gets the bundle object with the given id.
+ * @param bundleId the bundle id
+ * @return the bundle object
+ * @see org.osgi.framework.BundleContext#getBundle(long)
+ */
+ public Bundle getBundle(long bundleId) {
+ return m_global.getBundle(bundleId);
+ }
+
+ /**
+ * Gets installed bundles.
+ * @return the list of installed bundles
+ * @see org.osgi.framework.BundleContext#getBundles()
+ */
+ public Bundle[] getBundles() {
+ return m_global.getBundles();
+ }
+
+
+ /**
+ * Gets a data file.
+ * @param filename the File name.
+ * @return the File object
+ * @see org.osgi.framework.BundleContext#getDataFile(java.lang.String)
+ */
+ public File getDataFile(String filename) {
+ return m_global.getDataFile(filename);
+ }
+
+ /**
+ * Gets a property value.
+ * @param key the key of the asked property
+ * @return the property value (object) or <code>null</code> if no property
+ * are associated with the given key
+ * @see org.osgi.framework.BundleContext#getProperty(java.lang.String)
+ */
+ public String getProperty(String key) {
+ return m_global.getProperty(key);
+ }
+
+ /**
+ * Installs a bundle.
+ * @param location the URL of the bundle to install
+ * @return the installed bundle
+ * @throws BundleException if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String)
+ */
+ public Bundle installBundle(String location) throws BundleException {
+ return m_global.installBundle(location);
+ }
+
+ /**
+ * Installs a bundle.
+ * @param location the URL of the bundle to install
+ * @param input the input stream to load the bundle content
+ * @return the installed bundle
+ * @throws BundleException if the bundle cannot be installed correctly
+ * @see org.osgi.framework.BundleContext#installBundle(java.lang.String, java.io.InputStream)
+ */
+ public Bundle installBundle(String location, InputStream input) throws BundleException {
+ return m_global.installBundle(location, input);
+ }
+
+ /**
+ * Removes the bundle listener.
+ * @param listener the listener to remove
+ * @see org.osgi.framework.BundleContext#removeBundleListener(org.osgi.framework.BundleListener)
+ */
+ public void removeBundleListener(BundleListener listener) {
+ m_global.removeBundleListener(listener);
+ }
+
+ /**
+ * Removes a framework listener.
+ * @param listener the listener to remove
+ * @see org.osgi.framework.BundleContext#removeFrameworkListener(org.osgi.framework.FrameworkListener)
+ */
+ public void removeFrameworkListener(FrameworkListener listener) {
+ m_global.removeFrameworkListener(listener);
+ }
+
+ /**
+ * Registers a service.
+ * Operation not supported.
+ * @param clazz the class object
+ * @param svc the service object
+ * @param properties the properties
+ * @param <S> the type of service
+ * @return the service registration
+ */
+ public <S> ServiceRegistration<S> registerService(Class<S> clazz, S svc, Dictionary<String, ?> properties) {
+ throw new UnsupportedOperationException("PolicyServiceContext can only be used for service dependency and not to provide services");
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
new file mode 100644
index 0000000..b45a689
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveHandler.java
@@ -0,0 +1,257 @@
+/*
+ * 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;
+
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Logger;
+
+
+/**
+* This class defines common mechanisms of primitive handlers.
+* Primitive handlers are handler composing the container of primitive
+* component instances (declared by the 'component' element inside the
+* iPOJO descriptor).
+* Note that this class also defines default method implementation.
+* Classes overriding this class can change the behavior of those methods.
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+public abstract class PrimitiveHandler extends Handler implements FieldInterceptor, MethodInterceptor,
+ ConstructorInjector {
+
+ /**
+ * The "Primitive" Handler type (value).
+ */
+ public static final String HANDLER_TYPE = "primitive";
+
+ /**
+ * The reference on the instance manager.
+ */
+ private InstanceManager m_manager;
+
+
+ /**
+ * The factory of the instance manager.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Instance Logger used by the handler.
+ */
+ private Logger m_instanceLogger;
+
+ /**
+ * Attaches the current handler to the given instance.
+ * This method must be called only once, and should not be overridden.
+ * @param manager the instance on which the current handler will be attached.
+ * @see org.apache.felix.ipojo.Handler#attach(org.apache.felix.ipojo.ComponentInstance)
+ */
+ protected void attach(ComponentInstance manager) {
+ m_manager = (InstanceManager) manager;
+ m_instanceLogger = m_manager.getLogger();
+ }
+
+ /**
+ * Sets the factory of the managed instance.
+ * @param factory the factory
+ * @see org.apache.felix.ipojo.Handler#setFactory(org.apache.felix.ipojo.Factory)
+ */
+ public final void setFactory(Factory factory) {
+ m_factory = (ComponentFactory) factory;
+ }
+
+ /**
+ * Gets the logger of the managed instance.
+ * IF no instance attached yet, use the factory logger.
+ * @return the logger to use to log messages.
+ * @see org.apache.felix.ipojo.Handler#getLogger()
+ */
+ public Logger getLogger() {
+ if (m_instanceLogger == null) {
+ return m_factory.getLogger();
+ }
+ return m_instanceLogger;
+ }
+
+ /**
+ * Gets the instance manager managing the instance.
+ * @return the instance manager
+ */
+ public InstanceManager getInstanceManager() {
+ return m_manager;
+ }
+
+ /**
+ * Gets the factory which creates the managed instance.
+ * @return the factory which creates the managed instance.
+ */
+ public ComponentFactory getFactory() {
+ return m_factory;
+ }
+
+ /**
+ * Gets the PojoMetadata of the content of the managed
+ * instance. This method allows getting manipulation
+ * metadata.
+ * @return the information about the content of the
+ * managed instance.
+ */
+ public PojoMetadata getPojoMetadata() {
+ return m_factory.getPojoMetadata();
+ }
+
+ /**
+ * Gets a plugged handler of the same container.
+ * This method must be called only in the start method (or after).
+ * In the configure method, this method can be inconsistent
+ * as all handlers are not initialized.
+ * @param name the name of the handler to find (class name or qualified
+ * handler name (<code>ns:name</code>)).
+ * @return the handler object or <code>null</code> if the handler is not found.
+ */
+ public final Handler getHandler(String name) {
+ return m_manager.getHandler(name);
+ }
+
+ /**
+ * Callback method called when a managed field
+ * receives a new value. The given pojo can be
+ * null if the new value is set by another handler.
+ * This default implementation does nothing.
+ * @param pojo the pojo object setting the value
+ * @param fieldName the field name
+ * @param value the value received by the field
+ * @see FieldInterceptor#onSet(Object, String, Object)
+ */
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Nothing to do in the default implementation
+ }
+
+ /**
+ * Callback method called when a managed field
+ * asks for a value.
+ * The default implementation returned the previously
+ * injected value.
+ * @param pojo the pojo object requiring the value
+ * @param fieldName the field name
+ * @param value the value passed to the field (by the previous call)
+ * @return the value to inject, of the previous value if the handler
+ * don't want to inject a value.
+ * @see FieldInterceptor#onGet(Object, String, Object)
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+ return value;
+ }
+
+ /**
+ * Gets the object to inject as a constructor parameter
+ * @param index the index of the parameter
+ * @return the object to inject, or <code>null</code> if no
+ * objects are injected. This implementation returns <code>null</code>
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
+ */
+ public Object getConstructorParameter(int index) {
+ return null;
+ }
+
+ /**
+ * Gets the type of the object to inject in the constructor parameter.
+ * This is the type looked into the Pojo class, so it must match.
+ * Returning <code>null</code> will try to get the class from the
+ * injected object, however this can be wrong (implementation instead of interface,
+ * boxed objects...) and error-prone.
+ * @param index the parameter index
+ * @return the Class object (must fit for primitive type), this implementation
+ * just returns <code>null</code>
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
+ */
+ public Class getConstructorParameterType(int index) {
+ return null;
+ }
+
+ /**
+ * Callback method called when a method will be invoked.
+ * This default implementation does nothing.
+ * @param pojo the pojo on which the method is called.
+ * @param method the method invoked.
+ * @param args the arguments array.
+ * @see MethodInterceptor#onEntry(Object, java.lang.reflect.Member, Object[])
+ */
+ public void onEntry(Object pojo, Member method, Object[] args) {
+ // Nothing to do in the default implementation
+ }
+
+ /**
+ * Callback method called when a method ends.
+ * This method is called when a thread exits a method (before a return or a throw).
+ * If the given returned object is <code>null</code>, either the method is
+ * <code>void</code>, or it returns <code>null</code>.
+ * You must not modified the returned object.
+ * The default implementation does nothing.
+ * @param pojo the pojo on which the method exits.
+ * @param method the exiting method.
+ * @param returnedObj the returned object (boxed for primitive type)
+ * @see MethodInterceptor#onExit(Object, java.lang.reflect.Member, Object)
+ */
+ public void onExit(Object pojo, Member method, Object returnedObj) {
+ // Nothing to do in the default implementation
+ }
+
+ /**
+ * Callback method called when an error occurs.
+ * This method is called when the execution throws an exception
+ * in the given method.
+ * The default implementation does nothing.
+ * @param pojo the pojo on which the method was accessed.
+ * @param method the invoked method.
+ * @param throwable the thrown exception
+ * @see org.apache.felix.ipojo.MethodInterceptor#onError(Object, java.lang.reflect.Member, Throwable)
+ */
+ public void onError(Object pojo, Member method, Throwable throwable) {
+ // Nothing to do in the default implementation
+ }
+
+ /**
+ * Callback method called when the execution of a method will terminate :
+ * just before to throw an exception or before to return. This callback is called after
+ * {@link MethodInterceptor#onExit(Object, java.lang.reflect.Member, Object)} and
+ * {@link MethodInterceptor#onError(Object, java.lang.reflect.Member, Throwable)}
+ * This default implementation does nothing.
+ * @param pojo the pojo on which the method was accessed.
+ * @param method the invoked method.
+ */
+ public void onFinally(Object pojo, Member method) {
+ // Nothing to do in the default implementation
+ }
+
+ /**
+ * Callback method called when an instance of the component is created, but
+ * before someone can use it.
+ * The default implementation does nothing.
+ * @param instance the created instance
+ */
+ public void onCreation(Object instance) {
+ // Nothing to do in the default implementation
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveInstanceDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveInstanceDescription.java
new file mode 100644
index 0000000..e066251
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveInstanceDescription.java
@@ -0,0 +1,178 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandler;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandlerDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Primitive Instance Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PrimitiveInstanceDescription extends InstanceDescription {
+
+ /**
+ * Creates a Primitive Instance Description.
+ * @param type the component type description
+ * @param instance the instance description
+ */
+ public PrimitiveInstanceDescription(ComponentTypeDescription type, InstanceManager instance) {
+ super(type, instance);
+ }
+
+ /**
+ * Gets the list of object created by the described instance.
+ * @return the created objects.
+ */
+ public String[] getCreatedObjects() {
+ Object [] objs = ((InstanceManager) m_instance).getPojoObjects();
+ if (objs != null) {
+ String[] result = new String[objs.length];
+ for (int i = 0; i < objs.length; i++) {
+ result[i] = objs[i].toString();
+ }
+ return result;
+ } else {
+ return new String[0];
+ }
+ }
+
+ /**
+ * Gets the instance service dependencies.
+ * @return the set of dependency description or an empty array if
+ * no dependencies.
+ */
+ public DependencyDescription[] getDependencies() {
+ Handler handler = ((InstanceManager) m_instance).getHandler("org.apache.felix.ipojo:requires");
+ if (handler == null) {
+ return new DependencyDescription[0];
+ } else {
+ return ((DependencyHandlerDescription) ((DependencyHandler) handler)
+ .getDescription()).getDependencies();
+ }
+ }
+
+ /**
+ * Gets the instance service dependency matching with the given service specification or id.
+ * @param specification the service specification of the looked specification.
+ * @return the dependency description matching with the given service specification or id.
+ * <code>null</code> is not found.
+ * no dependencies.
+ */
+ public DependencyDescription getDependency(String specification) {
+ DependencyDescription[] deps = getDependencies();
+ if (deps == null) {
+ return null;
+ } else {
+ for (int i = 0; i < deps.length; i++) {
+ if (specification.equals(deps[i].getId())
+ || specification.equals(deps[i].getSpecification())) {
+ return deps[i];
+ }
+
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the instance provided service matching with the given service specification.
+ * @param specification the provided specification of the looked provided service.
+ * @return the provided service description matching with the given service specification.
+ * <code>null</code> is not found.
+ */
+ public ProvidedServiceDescription getProvidedService(String specification) {
+ ProvidedServiceDescription[] pss = getProvidedServices();
+ if (pss == null) {
+ return null;
+ } else {
+ for (int i = 0; i < pss.length; i++) {
+ String[] str = pss[i].getServiceSpecifications();
+ for (int j = 0; j < str.length; j++) {
+ if (specification.equals(str[j])) {
+ return pss[i];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the instance provided service.
+ * @return the set of provided service description or an empty array if
+ * no provided services.
+ */
+ public ProvidedServiceDescription[] getProvidedServices() {
+ Handler handler = ((InstanceManager) m_instance).getHandler("org.apache.felix.ipojo:provides");
+ if (handler == null) {
+ return new ProvidedServiceDescription[0];
+ } else {
+ return ((ProvidedServiceHandlerDescription) ((ProvidedServiceHandler) handler)
+ .getDescription()).getProvidedServices();
+ }
+ }
+
+ /**
+ * Gets the instance properties.
+ * @return the set of property descriptions or an empty array if
+ * no properties.
+ */
+ public PropertyDescription[] getProperties() {
+ Handler handler = ((InstanceManager) m_instance).getHandler("org.apache.felix.ipojo:properties");
+ if (handler == null) {
+ return new PropertyDescription[0];
+ } else {
+ return ((ConfigurationHandlerDescription) ((ConfigurationHandler) handler)
+ .getDescription()).getProperties();
+ }
+ }
+
+ /**
+ * Gets the instance description.
+ * Overridden to add created objects.
+ * @return the instance description
+ */
+ public Element getDescription() {
+ Element elem = super.getDescription();
+ // Created Object (empty is composite)
+ String[] objs = getCreatedObjects();
+ for (int i = 0; objs != null && i < objs.length; i++) {
+ Element obj = new Element("Object", "");
+ obj.addAttribute(new Attribute("name", ((Object) objs[i]).toString()));
+ elem.addElement(obj);
+ }
+ return elem;
+ }
+
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveTypeDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveTypeDescription.java
new file mode 100644
index 0000000..6e61112
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/PrimitiveTypeDescription.java
@@ -0,0 +1,228 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.osgi.framework.Bundle;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class defines the description of primitive (non-composite) component
+ * types. An instance of this class will be returned when invoking the
+ * {@link org.apache.felix.ipojo.ComponentFactory#getComponentDescription()} method.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+final class PrimitiveTypeDescription extends ComponentTypeDescription {
+
+ /**
+ * Set to keep component's all super-class class-names.
+ */
+ private Set<String> m_superClasses = new HashSet<String>();
+
+ /**
+ * Set to keep component's all interface class-names.
+ */
+ private Set<String> m_interfaces = new HashSet<String>();
+
+ /**
+ * The described component factory.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Creates a PrimitiveTypeDescription object.
+ *
+ * @param factory the m_factory attached to this component type description.
+ */
+ public PrimitiveTypeDescription(ComponentFactory factory) {
+ super(factory);
+ this.m_factory = factory;
+
+ try {
+ // The inspection can be done only for primitive components
+ if (factory.getClassName() != null) {
+ // Read inherited classes and interfaces into given Sets.
+ new InheritanceInspector(factory.getPojoMetadata(), getBundleContext().getBundle()).
+ computeInterfacesAndSuperClasses(m_interfaces, m_superClasses);
+ }
+ } catch (ClassNotFoundException e) {
+ m_interfaces.clear();
+ m_superClasses.clear();
+ }
+
+ }
+
+ /**
+ * Computes the properties to publish.
+ * The <code>component.class</code> property contains the implementation class name.
+ *
+ * @return the dictionary of properties to publish
+ * @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish()
+ */
+ public Dictionary<String, Object> getPropertiesToPublish() {
+ Dictionary<String, Object> dict = super.getPropertiesToPublish();
+ if (m_factory.getClassName() != null) {
+ dict.put("component.class", m_factory.getClassName());
+ }
+ return dict;
+ }
+
+ /**
+ * Adds the "implementation-class" attribute to the type description.
+ *
+ * @return the component type description.
+ * @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getDescription()
+ */
+ public Element getDescription() {
+ Element elem = super.getDescription();
+ elem.addAttribute(new Attribute("Implementation-Class", m_factory.getClassName()));
+
+ /* Adding interfaces and super-classes of component into description */
+ Element inheritance = new Element("Inherited", "");
+
+ inheritance.addAttribute(new Attribute("Interfaces", m_interfaces.toString()));
+ inheritance.addAttribute(new Attribute("SuperClasses", m_superClasses.toString()));
+
+ elem.addElement(inheritance);
+
+ return elem;
+ }
+
+ /**
+ * This class is used to collect interfaces and super-classes of given component in specified Sets.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+ private final class InheritanceInspector {
+ /*
+ * PojoMetadata of target Component.
+ */
+ private PojoMetadata m_pojoMetadata;
+ /*
+ * Bundle exposing target component.
+ */
+ private Bundle m_bundle;
+
+
+ /**
+ * Creates a TypeCollector object
+ *
+ * @param pojoMetadata PojoMetadata describing Component.
+ * @param bundle Bundle which has been exposed the intended Component.
+ */
+ public InheritanceInspector(PojoMetadata pojoMetadata, Bundle bundle) {
+ m_pojoMetadata = pojoMetadata;
+ m_bundle = bundle;
+ }
+
+ /**
+ * Collect interfaces implemented by the POJO into given Sets.
+ *
+ * @param interfaces : the set of implemented interfaces
+ * @param classes : the set of extended classes
+ * @throws ClassNotFoundException : occurs when an interface cannot be loaded.
+ */
+ public void computeInterfacesAndSuperClasses(Set<String> interfaces, Set<String> classes) throws ClassNotFoundException {
+ String[] immediateInterfaces = m_pojoMetadata.getInterfaces();
+ String parentClass = m_pojoMetadata.getSuperClass();
+
+ // First iterate on found specification in manipulation metadata
+ for (String immediateInterface : immediateInterfaces) {
+ interfaces.add(immediateInterface);
+ // Iterate on interfaces implemented by the current interface
+ Class<?> clazz = m_bundle.loadClass(immediateInterface);
+ collectInterfaces(clazz, interfaces, m_bundle);
+ }
+
+ // Look for parent class.
+ if (parentClass != null) {
+ Class clazz = m_bundle.loadClass(parentClass);
+ collectInterfacesFromClass(clazz, interfaces, m_bundle);
+ classes.add(parentClass);
+ collectParentClassesFromClass(clazz, classes, m_bundle);
+ }
+
+ // Removing Object Class from the inherited classes list.
+ classes.remove(Object.class.getName());
+ }
+
+ /**
+ * Look for inherited interfaces.
+ *
+ * @param clazz : interface name to explore (class object)
+ * @param acc : set (accumulator)
+ * @param bundle : bundle
+ * @throws ClassNotFoundException : occurs when an interface cannot be loaded.
+ */
+ private void collectInterfaces(Class<?> clazz, Set<String> acc, Bundle bundle) throws ClassNotFoundException {
+ Class[] clazzes = clazz.getInterfaces();
+ for (Class clazze : clazzes) {
+ acc.add(clazze.getName());
+ collectInterfaces(clazze, acc, bundle);
+ }
+ }
+
+ /**
+ * Collect interfaces for the given class.
+ * This method explores super class to.
+ *
+ * @param clazz : class object.
+ * @param acc : set of implemented interface (accumulator)
+ * @param bundle : bundle.
+ * @throws ClassNotFoundException : occurs if an interface cannot be load.
+ */
+ private void collectInterfacesFromClass(Class<?> clazz, Set<String> acc,
+ Bundle bundle) throws ClassNotFoundException {
+ Class[] clazzes = clazz.getInterfaces();
+ for (Class clazze : clazzes) {
+ acc.add(clazze.getName());
+ collectInterfaces(clazze, acc, bundle);
+ }
+ // Iterate on parent classes
+ Class sup = clazz.getSuperclass();
+ if (sup != null) {
+ collectInterfacesFromClass(sup, acc, bundle);
+ }
+ }
+
+ /**
+ * Collect parent classes for the given class.
+ *
+ * @param clazz : class object.
+ * @param acc : set of extended classes (accumulator)
+ * @param bundle : bundle.
+ * @throws ClassNotFoundException : occurs if an interface cannot be load.
+ */
+ private void collectParentClassesFromClass(Class<?> clazz, Set<String> acc, Bundle bundle) throws ClassNotFoundException {
+ Class<?> parent = clazz.getSuperclass();
+ if (parent != null) {
+ acc.add(parent.getName());
+ collectParentClassesFromClass(parent, acc, bundle);
+ }
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ServiceContext.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ServiceContext.java
new file mode 100644
index 0000000..7d3765c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ServiceContext.java
@@ -0,0 +1,149 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * A service context is the facade of a service registry.
+ * It gives the access to a service broker. All service
+ * interactions should use a service context to garanty
+ * the service isolation.
+ * This class is a subset of {@link BundleContext} methods.
+ * (methods implying interactions with the service registry).
+ * So, refer to this class for further information.
+ * @see BundleContext
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceContext extends BundleContext {
+
+ /**
+ * Adds a service listener.
+ * The listener is added to this service context.
+ * So only services from this context will be tracked.
+ * @param listener the service listener to add.
+ * @param filter the LDAP filter
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String)
+ */
+ void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException;
+
+ /**
+ * Adds a service listener.
+ * The listener is added to this service context.
+ * So only services from this context will be tracked.
+ * @param listener the service listener to add.
+ * @see org.osgi.framework.BundleContext#addServiceListener(org.osgi.framework.ServiceListener)
+ */
+ void addServiceListener(ServiceListener listener);
+
+ /**
+ * Gets the service references matching with the given query.
+ * The query is executed inside this service context.
+ * @param clazz the required interface
+ * @param filter a LDAP filter
+ * @return the array of available service references or <code>null</code>
+ * if no providers are available.
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#getAllServiceReferences(java.lang.String, java.lang.String)
+ */
+ ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException;
+
+ /**
+ * Gets a service object.
+ * The given service reference must comes from this
+ * service context.
+ * @param reference the required service reference
+ * @return the service object or null if the service reference is no more valid or if the service object is not accessible
+ * @see org.osgi.framework.BundleContext#getService(org.osgi.framework.ServiceReference)
+ */
+ <S> S getService(ServiceReference<S> reference);
+
+ /**
+ * Gets a service reference for the given interface.
+ * The query is executed inside this service context.
+ * @param clazz the required interface name
+ * @return a service reference on a available provider or
+ * <code>null</code> if no providers are available
+ * @see org.osgi.framework.BundleContext#getServiceReference(java.lang.String)
+ */
+ ServiceReference getServiceReference(String clazz);
+
+ /**
+ * Gets service reference list for the given query.
+ * The query is executed inside this service context.
+ * @param clazz : the name of the required service interface
+ * @param filter : LDAP filter to apply on service provider
+ * @return : the array of consistent service reference or <code>null</code>
+ * if no available providers
+ * @throws InvalidSyntaxException if the LDAP filter is malformed
+ * @see org.osgi.framework.BundleContext#getServiceReferences(java.lang.String, java.lang.String)
+ */
+ ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException;
+
+ /**
+ * Registers a service inside this service context.
+ * This service is then isolated inside this context.
+ * @param clazzes the interfaces provided by the service.
+ * @param service the service object.
+ * @param properties service properties to publish
+ * @return the service registration for this service publication.
+ * This service registration is attached to the current service context,
+ * and does not have any meaning in other contexts.
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ ServiceRegistration registerService(String[] clazzes, Object service, Dictionary<String, ?> properties);
+
+ /**
+ * Registers a service inside this service context.
+ * This service is then isolated inside this context.
+ * @param clazz the interface provided by the service.
+ * @param service the service object.
+ * @param properties service properties to publish.
+ * @return the service registration for this service publication.
+ * This service registration is attached to the current service context,
+ * and does not have any meaning in other contexts.
+ * @see org.osgi.framework.BundleContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+ */
+ ServiceRegistration registerService(String clazz, Object service, Dictionary<String, ?> properties);
+
+ /**
+ * Removes a service listener.
+ * The listener must be registered inside this service context.
+ * @param listener the listener to remove
+ * @see org.osgi.framework.BundleContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ */
+ void removeServiceListener(ServiceListener listener);
+
+ /**
+ * Ungets the service reference.
+ * The service reference must comes from this service context.
+ * @param reference the reference to unget
+ * @return <code>true</code> if you are the last user of the reference.
+ * @see org.osgi.framework.BundleContext#ungetService(org.osgi.framework.ServiceReference)
+ */
+ boolean ungetService(ServiceReference<?> reference);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/UnacceptableConfiguration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/UnacceptableConfiguration.java
new file mode 100644
index 0000000..63f0f13
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/UnacceptableConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * UnacceptableConfiguration occurs when a factory refuses to create an
+ * instance. This exception is thrown when the instance configuration does not
+ * specify a value for a required property or when the configuration tries to override
+ * the value of an immutable property
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class UnacceptableConfiguration extends Exception {
+
+ /**
+ * Exception UID.
+ */
+ private static final long serialVersionUID = 2998931848886223965L;
+
+ /**
+ * Creates an UnacceptableConfiguration.
+ * @param message message about the error.
+ */
+ public UnacceptableConfiguration(String message) {
+ this(message, null);
+ }
+
+ public UnacceptableConfiguration(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java
new file mode 100644
index 0000000..424e8fd
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java
@@ -0,0 +1,40 @@
+/*
+ * 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.architecture;
+
+/**
+ * Architecture service.
+ * This service allows collecting information on the component instance,
+ * such as its state, plugged handlers ...
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Architecture {
+
+ /**
+ * Architecture service must published this property telling which instance they are representing.
+ */
+ public static final String ARCHITECTURE_INSTANCE = "architecture.instance";
+
+ /**
+ * Returns the description of the instance.
+ * @return the component instance description
+ */
+ InstanceDescription getInstanceDescription();
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java
new file mode 100644
index 0000000..86a171f
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java
@@ -0,0 +1,318 @@
+/*
+ * 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.architecture;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Component Type description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentTypeDescription {
+
+ /**
+ * Represented factory.
+ */
+ private final IPojoFactory m_factory;
+ /**
+ * Provided service by the component type.
+ */
+ private String[] m_providedServiceSpecification = new String[0];
+ /**
+ * Configuration Properties accepted by the component type.
+ */
+ private PropertyDescription[] m_properties = new PropertyDescription[0];
+ /*
+ * Used by custom handlers to keep and retrieve custom info.
+ */
+ private Dictionary m_handlerInfoSlot = new Hashtable();
+
+ /**
+ * Constructor.
+ *
+ * @param factory : represented factory.
+ */
+ public ComponentTypeDescription(IPojoFactory factory) {
+ m_factory = factory;
+ }
+
+ /**
+ * Gets the attached factory.
+ *
+ * @return the factory
+ */
+ public IPojoFactory getFactory() {
+ return m_factory;
+ }
+
+ /**
+ * Gets a printable form of the current component type description.
+ *
+ * @return printable form of the component type description
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return getDescription().toString();
+ }
+
+ /**
+ * Gets the implementation class of this component type.
+ *
+ * @return the component type implementation class name.
+ * @deprecated
+ */
+ public String getClassName() {
+ return m_factory.getClassName();
+ }
+
+ /**
+ * Gets the component type version.
+ *
+ * @return the component type version or
+ * <code>null</code> if not set.
+ */
+ public String getVersion() {
+ return m_factory.getVersion();
+ }
+
+ /**
+ * Gets component-type properties.
+ *
+ * @return the list of configuration properties accepted by the component type type.
+ */
+ public PropertyDescription[] getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * Adds a String property in the component type.
+ *
+ * @param name : property name.
+ * @param value : property value.
+ */
+ public void addProperty(String name, String value) {
+ addProperty(name, value, false);
+ }
+
+ /**
+ * Adds a String property in the component type.
+ *
+ * @param name : property name.
+ * @param value : property value.
+ * @param immutable : the property is immutable.
+ */
+ public void addProperty(String name, String value, boolean immutable) {
+ addProperty(new PropertyDescription(name, String.class.getName(), value, immutable));
+ }
+
+ /**
+ * Adds a configuration properties to the component type.
+ *
+ * @param pd : the property to add
+ */
+ public void addProperty(PropertyDescription pd) { //NOPMD remove the instance name of the 'name' property.
+ String name = pd.getName();
+
+ // Check if the property is not already in the array
+ for (int i = 0; i < m_properties.length; i++) {
+ PropertyDescription desc = m_properties[i];
+ if (desc.getName().equals(name)) {
+ return;
+ }
+ }
+
+ PropertyDescription[] newProps = new PropertyDescription[m_properties.length + 1];
+ System.arraycopy(m_properties, 0, newProps, 0, m_properties.length);
+ newProps[m_properties.length] = pd;
+ m_properties = newProps;
+ }
+
+ /**
+ * Adds the HandlerInfo for specified handler.
+ *
+ * @param handlerNs Handler's namespace
+ * @param handlerName Handler's name
+ * @param info HandlerInfo associated with the given custom handler.
+ */
+ public void setHandlerInfo(String handlerNs, String handlerName, CustomHandlerInfo info) {
+ String fullHandlerName = handlerNs + ":" + handlerName;
+
+ if (info == null) {
+ m_handlerInfoSlot.remove(fullHandlerName);
+ } else {
+ m_handlerInfoSlot.put(fullHandlerName, info);
+ }
+ }
+
+ public CustomHandlerInfo getHandlerInfo(String handlerNs, String handlerName) {
+ String fullHandlerName = handlerNs + ":" + handlerName;
+ return (CustomHandlerInfo) m_handlerInfoSlot.get(fullHandlerName);
+ }
+
+ /**
+ * Gets the list of provided service offered by instances of this type.
+ *
+ * @return the list of the provided service.
+ */
+ public String[] getprovidedServiceSpecification() {
+ return m_providedServiceSpecification;
+ }
+
+ /**
+ * Adds a provided service to the component type.
+ *
+ * @param serviceSpecification : the provided service to add (interface name)
+ */
+ public void addProvidedServiceSpecification(String serviceSpecification) {
+ String[] newSs = new String[m_providedServiceSpecification.length + 1];
+ System.arraycopy(m_providedServiceSpecification, 0, newSs, 0, m_providedServiceSpecification.length);
+ newSs[m_providedServiceSpecification.length] = serviceSpecification;
+ m_providedServiceSpecification = newSs;
+ }
+
+ /**
+ * Returns the component-type name.
+ *
+ * @return the name of this component type
+ */
+ public String getName() {
+ return m_factory.getName();
+ }
+
+ /**
+ * Computes the default service properties to publish :
+ * factory.name, service.pid, component.providedServiceSpecification, component.properties, component.description, factory.State.
+ *
+ * @return : the dictionary of properties to publish.
+ */
+ public Dictionary<String, Object> getPropertiesToPublish() {
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+
+ props.put("factory.name", m_factory.getName());
+ props.put(Constants.SERVICE_PID, m_factory.getName()); // Service PID is required for the integration in the configuration admin.
+
+ // Add the version if set
+ String v = getVersion();
+ if (v != null) {
+ props.put(Factory.FACTORY_VERSION_PROPERTY, v);
+ }
+
+ props.put("component.providedServiceSpecifications", m_providedServiceSpecification);
+ props.put("component.properties", m_properties);
+ props.put("component.description", this);
+
+ // add every immutable property
+ for (PropertyDescription m_property : m_properties) {
+ if (m_property.isImmutable() && m_property.getValue() != null) {
+ props.put(m_property.getName(), m_property.getObjectValue(m_factory.getBundleContext()));
+ }
+ }
+
+ // Add factory state
+ props.put("factory.state", m_factory.getState());
+
+ return props;
+
+ }
+
+ /**
+ * Gets the interfaces published by the factory.
+ * By default publish both {@link Factory} and {@link ManagedServiceFactory}.
+ *
+ * @return : the list of interface published by the factory.
+ */
+ public String[] getFactoryInterfacesToPublish() {
+ return new String[]{Factory.class.getName()};
+ }
+
+ /**
+ * Gets the component type description.
+ *
+ * @return : the description
+ */
+ public Element getDescription() {
+ Element desc = new Element("Factory", "");
+
+ desc.addAttribute(new Attribute("name", m_factory.getName()));
+ desc.addAttribute(
+ new Attribute("bundle",
+ Long.toString(m_factory.getBundleContext().getBundle().getBundleId())));
+
+ String state = "valid";
+ if (m_factory.getState() == Factory.INVALID) {
+ state = "invalid";
+ }
+ desc.addAttribute(new Attribute("state", state));
+
+ // Display required & missing handlers
+ Element req = new Element("RequiredHandlers", "");
+ req.addAttribute(new Attribute("list", m_factory.getRequiredHandlers().toString()));
+ Element missing = new Element("MissingHandlers", "");
+ missing.addAttribute(new Attribute("list", m_factory.getMissingHandlers().toString()));
+ desc.addElement(req);
+ desc.addElement(missing);
+
+ for (int i = 0; i < m_providedServiceSpecification.length; i++) {
+ Element prov = new Element("provides", "");
+ prov.addAttribute(new Attribute("specification", m_providedServiceSpecification[i]));
+ desc.addElement(prov);
+ }
+
+ for (int i = 0; i < m_properties.length; i++) {
+ Element prop = new Element("property", "");
+ prop.addAttribute(new Attribute("name", m_properties[i].getName()));
+ prop.addAttribute(new Attribute("type", m_properties[i].getType()));
+ if (m_properties[i].isMandatory() && m_properties[i].getValue() == null) {
+ prop.addAttribute(new Attribute("value", "REQUIRED"));
+ } else {
+ prop.addAttribute(new Attribute("value", m_properties[i].getValue()));
+ }
+ desc.addElement(prop);
+ }
+
+ if (m_handlerInfoSlot.size() > 0) {
+ Enumeration keys = m_handlerInfoSlot.keys();
+
+ while (keys.hasMoreElements()) {
+ String fullHandlerName = (String) keys.nextElement();
+
+ CustomHandlerInfo handlerInfo = (CustomHandlerInfo) m_handlerInfoSlot.get(fullHandlerName);
+ desc.addElement(handlerInfo.getDescription());
+ }
+ }
+
+ return desc;
+ }
+
+ public BundleContext getBundleContext() {
+ return m_factory.getBundleContext();
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/CustomHandlerInfo.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/CustomHandlerInfo.java
new file mode 100644
index 0000000..8bfb023
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/CustomHandlerInfo.java
@@ -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.architecture;
+
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Information slot for custom {@link Handler}s to put their own custom
+ * information into {@link ComponentTypeDescription}
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface CustomHandlerInfo
+{
+ /**
+ * Returns the custom handler information in readable
+ * format to be displayed in ComponentTypeDescription.
+ * @return Custom Handler information
+ */
+ Element getDescription();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/HandlerDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/HandlerDescription.java
new file mode 100644
index 0000000..ffc64c8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/HandlerDescription.java
@@ -0,0 +1,86 @@
+/*
+ * 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.architecture;
+
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Handler Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerDescription {
+
+ /**
+ * The Handler Qualified Name.
+ */
+ private String m_handlerName;
+
+
+ /**
+ * The described handler instance.
+ */
+ private Handler m_handler;
+
+ /**
+ * Creates a handler description.
+ * @param handler the handler.
+ */
+ public HandlerDescription(Handler handler) {
+ HandlerFactory factory = (HandlerFactory) handler.getHandlerManager().getFactory();
+ m_handlerName = factory.getHandlerName();
+ m_handler = handler;
+ }
+
+ /**
+ * Checks if the handler is valid.
+ * @return true if the handler is valid.
+ */
+ public boolean isValid() {
+ return m_handler.isValid();
+ }
+
+ /**
+ * Gets the handler name.
+ * @return the handler qualified name (i.e. namespace:name).
+ */
+ public String getHandlerName() {
+ return m_handlerName;
+ }
+
+ /**
+ * Gets handler information.
+ * This represent the actual state of the handler.
+ * @return the handler information.
+ */
+ public Element getHandlerInfo() {
+ Element elem = new Element("Handler", "");
+ elem.addAttribute(new Attribute("name", m_handlerName));
+ if (isValid()) {
+ elem.addAttribute(new Attribute("state", "valid"));
+ } else {
+ elem.addAttribute(new Attribute("state", "invalid"));
+ }
+ return elem;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java
new file mode 100644
index 0000000..c1907e9
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java
@@ -0,0 +1,203 @@
+/*
+ * 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.architecture;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Instance Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstanceDescription implements InstanceStateListener {
+
+ /**
+ * The list of handlers plugged on the component instance.
+ */
+ protected HandlerDescription[] m_handlers;
+
+ /**
+ * The Underlying component instance.
+ */
+ protected final ComponentInstance m_instance;
+
+ /**
+ * Component Type of the instance.
+ */
+ protected final ComponentTypeDescription m_type;
+
+ /**
+ * Creates the instance description.
+ * @param ci the state of the instance.
+ * @param desc the component type description of this instance.
+ */
+ public InstanceDescription(ComponentTypeDescription desc, ComponentInstance ci) {
+ m_handlers = new HandlerDescription[0];
+ m_type = desc;
+ m_instance = ci;
+ m_instance.addInstanceStateListener(this);
+ }
+
+ /**
+ * Gets the underlying component instance
+ * @return the component instance.
+ */
+ public ComponentInstance getInstance() {
+ return m_instance;
+ }
+
+ /**
+ * Gets the instance name.
+ * @return the name of the instance.
+ */
+ public String getName() {
+ return m_instance.getInstanceName();
+ }
+
+ /**
+ * Gets the component type description of the described instance.
+ * @return : the component type description of this instance.
+ */
+ public ComponentTypeDescription getComponentDescription() {
+ return m_type;
+ }
+
+ /**
+ * Gets the plugged handler list.
+ * @return the live handler list
+ */
+ public HandlerDescription[] getHandlers() {
+ return m_handlers;
+ }
+
+ /**
+ * Adds an handler description to the list.
+ * @param desc : the handler description to add
+ */
+ public void addHandler(HandlerDescription desc) {
+ // Verify that the dependency description is not already in the array.
+ for (HandlerDescription handler : m_handlers) {
+ if (handler == desc) {
+ return; // NOTHING TO DO, the description is already in the
+ // array
+ }
+ }
+ // The component Description is not in the array, add it
+ HandlerDescription[] newHd = new HandlerDescription[m_handlers.length + 1];
+ System.arraycopy(m_handlers, 0, newHd, 0, m_handlers.length);
+ newHd[m_handlers.length] = desc;
+ m_handlers = newHd;
+ }
+
+ /**
+ * Gets a handler description by specifying the handler qualified name.
+ * This method ignores case of the given handler name.
+ * @param handler the handler name
+ * @return the handler description or <code>null</code> if not found
+ */
+ public HandlerDescription getHandlerDescription(String handler) {
+ for (HandlerDescription description : m_handlers) {
+ if (description.getHandlerName().equalsIgnoreCase(handler)) {
+ return description;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the state of the described instance.
+ * @return the state of the instance.
+ */
+ public int getState() {
+ waitForStability();
+ return m_instance.getState();
+ }
+
+ /**
+ * Gets the bundle id of the bundle containing the component type of the instance.
+ * @return the bundle id owning the component implementation class.
+ */
+ public long getBundleId() {
+ return m_instance.getFactory().getBundleContext().getBundle().getBundleId();
+ }
+
+ /**
+ * Gets the instance description.
+ * @return the instance description
+ */
+ public Element getDescription() {
+ Element instance = new Element("Instance", "");
+ instance.addAttribute(new Attribute("name", getName())); // Name
+
+ int state = getState();
+ if (state == ComponentInstance.STOPPED) {
+ instance.addAttribute(new Attribute("state", "stopped"));
+ }
+ if (state == ComponentInstance.VALID) {
+ instance.addAttribute(new Attribute("state", "valid"));
+ }
+ if (state == ComponentInstance.INVALID) {
+ instance.addAttribute(new Attribute("state", "invalid"));
+ }
+ if (state == ComponentInstance.DISPOSED) {
+ instance.addAttribute(new Attribute("state", "disposed"));
+ }
+ // Bundle
+ instance.addAttribute(new Attribute("bundle", Long.toString(getBundleId())));
+
+ // Component Type
+ instance.addAttribute(new Attribute("component.type", m_type.getName()));
+
+ // Handlers
+ for (HandlerDescription description : m_handlers) {
+ instance.addElement(description.getHandlerInfo());
+ }
+
+ return instance;
+
+ }
+
+ /**
+ * Waits for state stability before returning results.
+ */
+ private synchronized void waitForStability() {
+ while (m_instance.getState() == -2) { // Transition
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // We're interrupted, will re-check the condition.
+ }
+ }
+
+ }
+
+ /**
+ * The underlying instance state changes.
+ * @param instance the instance
+ * @param newState the new state
+ * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
+ */
+ public synchronized void stateChanged(ComponentInstance instance, int newState) {
+ notifyAll(); // if we were in a transition, the transition has completed.
+ }
+
+}
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
new file mode 100644
index 0000000..4f356fb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/PropertyDescription.java
@@ -0,0 +1,215 @@
+/*
+ * 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.architecture;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandler;
+import org.apache.felix.ipojo.util.Property;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Property Information.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PropertyDescription {
+
+ /**
+ * Name of the property.
+ */
+ private String m_name;
+
+ /**
+ * Type of the property.
+ */
+ private String m_type;
+
+ /**
+ * Value of the property.
+ */
+ private String m_value = null;
+
+ /**
+ * Attached property object.
+ */
+ private Property m_property;
+
+
+ /**
+ * Immutable property flag
+ * If set to <code>true</code>, the property cannot be override by the instance configuration.
+ * Moreover, immutable properties are exposed on the factory service too.
+ */
+ private boolean m_immutable = false;
+
+ /**
+ * A property is mandatory. So, either the component type description provides a value or
+ * the instance configuration must provide a value. Immutable properties are mandatories.
+ */
+ private boolean m_isMandatory = false;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the property
+ * @param type the type of the property
+ * @param value the default value of the property, can be <code>null</code>
+ */
+ public PropertyDescription(String name, String type, String value) {
+ m_name = name;
+ m_type = type;
+ m_value = value;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param prop the attache Property object.
+ */
+ public PropertyDescription(Property prop) {
+ m_property = prop;
+ m_name = prop.getName();
+ m_type = prop.getType();
+ m_value = null; // Living property, value will be asked at runtime.
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name the name of the property
+ * @param type the type of the property
+ * @param value the default value (String form) of the property, can be <code>null</code>
+ * @param immutable the property is immutable.
+ */
+ public PropertyDescription(String name, String type, String value, boolean immutable) {
+ m_name = name;
+ m_type = type;
+ m_value = value;
+ m_immutable = immutable;
+ }
+
+ /**
+ * Gets the current property name.
+ * @return the property name.
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * Gets the current property type.
+ * @return the property type.
+ */
+ public String getType() {
+ return m_type;
+ }
+
+ /**
+ * Gets the current property value.
+ * @return the default value for the property,
+ * <code>null</code> if the property hasn't a value..
+ */
+ public String getValue() {
+ if (m_property == null) {
+ return m_value;
+ } else {
+ Object value = m_property.getValue();
+ if (value == null) {
+ return "null";
+ } else if (value == Property.NO_VALUE) {
+ return Property.UNVALUED;
+ } else {
+ return value.toString();
+ }
+ }
+ }
+
+ /**
+ * Sets the property value.
+ * This method can only be called on 'living' property
+ * (properties with a {@link Property} object).
+ * @param value the new value.
+ */
+ public void setValue(Object value) {
+ if (m_property == null) {
+ throw new UnsupportedOperationException("Cannot set the value of a non 'living' property");
+ } else {
+ ConfigurationHandler handler = (ConfigurationHandler) m_property.getHandler();
+ handler.reconfigureProperty(m_property, value);
+ }
+ }
+
+ /**
+ * Is the property immutable.
+ * @return <code>true</code> if the property is immutable.
+ */
+ public boolean isImmutable() {
+ return m_immutable;
+ }
+
+ /**
+ * Sets the property as mandatory.
+ */
+ public void setMandatory() {
+ m_isMandatory = true;
+ }
+
+ /**
+ * Is the property mandatory.
+ * @return <code>true</code> if the property is mandatory,
+ * <code>false</code> otherwise.
+ */
+ public boolean isMandatory() {
+ return m_isMandatory;
+ }
+
+ /**
+ * Gets the object value of the current immutable property.
+ * @param context the bundle context to use to load classes.
+ * @return the object value of the current property or <code>
+ * null</code> if the current value is <code>null</code>.
+ */
+ public Object getObjectValue(BundleContext context) {
+ if (m_value == null) {
+ return null;
+ }
+
+ Class type = null;
+ try {
+ type = Property.computeType(m_type, context);
+ return Property.create(type, m_value);
+ } catch (ConfigurationException e) {
+ return m_value; // Cannot create the object.
+ }
+ }
+
+ /**
+ * Gets the current value of the property as object.
+ * @return the current value
+ * @since 1.11.1
+ */
+ public Object getCurrentValue() {
+ if (m_property == null) {
+ return m_value;
+ } else {
+ return m_property.getValue();
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Configuration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Configuration.java
new file mode 100644
index 0000000..76f3720
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Configuration.java
@@ -0,0 +1,32 @@
+/*
+ * 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.configuration;
+
+/**
+ * A marker interface to detect configurations
+ */
+public @interface Configuration {
+
+ /**
+ * An optional name
+ * @return the optional configuration name
+ */
+ String value() default "";
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Instance.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Instance.java
new file mode 100644
index 0000000..3dd0794
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/configuration/Instance.java
@@ -0,0 +1,189 @@
+/*
+ * 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.configuration;
+
+import org.apache.felix.ipojo.Factory;
+
+import java.util.*;
+
+/**
+ * Instance Builder
+ */
+public class Instance {
+
+ private String factory;
+ private String name;
+ private List<Property> configuration;
+
+ public static Instance instance() {
+ return new Instance();
+ }
+
+ public static <T> FluentList<T> list(T... items) {
+ return new FluentList<T>(items);
+ }
+
+ public static <K, T> FluentMap<K, T> map(Pair<K, T>... pairs) {
+ return new FluentMap<K, T>(pairs);
+ }
+
+ public static <K, T> Pair<K, T> pair(K k, T v) {
+ return new Pair<K, T>(k, v);
+ }
+
+ public static <K, T> Pair<K, T> entry(K k, T v) {
+ return new Pair<K, T>(k, v);
+ }
+
+ public String factory() {
+ return factory;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public Dictionary<String, Object> configuration() {
+ Hashtable<String, Object> configuration = new Hashtable<String, Object>();
+ if (this.configuration != null) {
+ for (Property property : this.configuration) {
+ configuration.put(property.name, property.value);
+ }
+ }
+
+ if (name != null) {
+ configuration.put(Factory.INSTANCE_NAME_PROPERTY, name);
+ }
+
+ return configuration;
+ }
+
+ public Instance of(String factory) {
+ this.factory = factory;
+ return this;
+ }
+
+ public Instance of(Class clazz) {
+ this.factory = clazz.getName();
+ return this;
+ }
+
+ public Instance named(String name) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException("The instance name cannot be null or empty");
+ }
+ this.name = name;
+ return this;
+ }
+
+ public Instance.Property<Object> with(String property) {
+ if (this.configuration == null) {
+ this.configuration = new ArrayList<Property>();
+ }
+ Property<Object> prop = new Property<Object>(property);
+ this.configuration.add(prop);
+ return prop;
+ }
+
+ public Instance nameIfUnnamed(String name) {
+ if (this.name == null) {
+ named(name);
+ }
+ return this;
+ }
+
+ public static class FluentList<T> extends ArrayList<T> {
+
+ public FluentList() {
+ super(new ArrayList<T>());
+ }
+
+ public FluentList(T... items) {
+ this();
+ addAll(Arrays.asList(items));
+ }
+
+ public FluentList<T> with(T o) {
+ add(o);
+ return this;
+ }
+ }
+
+ public static class FluentMap<K, T> extends LinkedHashMap<K, T> {
+
+ public FluentMap() {
+ super(new LinkedHashMap<K, T>());
+ }
+
+ public FluentMap(Pair<? extends K, ? extends T>... pairs) {
+ this();
+ with(pairs);
+ }
+
+ public FluentMap<K, T> with(Pair<? extends K, ? extends T>... pairs) {
+ for (Pair<? extends K, ? extends T> pair : pairs) {
+ this.put(pair.key, pair.value);
+ }
+ return this;
+ }
+
+ public FluentMap<K, T> putAt(K k, T value) {
+ this.put(k, value);
+ return this;
+ }
+ }
+
+ public static class Pair<K, V> {
+ private final K key;
+ private final V value;
+
+ Pair(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+ }
+
+ public class Property<T> {
+
+ private final String name;
+ private T value;
+
+ Property(String name) {
+ if (name == null || name.length() == 0) {
+ throw new IllegalArgumentException("The property name cannot be null or empty");
+ }
+ this.name = name;
+ }
+
+ public Instance setto(T value) {
+ if ("instance.name".endsWith(name)) {
+ if (value == null || value.toString().length() == 0) {
+ throw new IllegalArgumentException("The instance name cannot be null or empty");
+ }
+ }
+ this.value = value;
+ return Instance.this;
+ }
+
+ public T get() {
+ return value;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceReferenceImpl.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceReferenceImpl.java
new file mode 100644
index 0000000..9889882
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceReferenceImpl.java
@@ -0,0 +1,156 @@
+/*
+ * 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.context;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Internal service reference implementation. This class is used for in the
+ * composition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceReferenceImpl implements ServiceReference {
+
+ /**
+ * Service Registration attached to the service reference.
+ */
+ private ServiceRegistrationImpl m_registration = null;
+
+ /**
+ * Component Instance.
+ */
+ private ComponentInstance m_cm;
+
+ /**
+ * Constructor.
+ *
+ * @param instance : component instance publishing the service.
+ * @param ref : registration attached to this service reference.
+ */
+ public ServiceReferenceImpl(ComponentInstance instance, ServiceRegistrationImpl ref) {
+ m_registration = ref;
+ m_cm = instance;
+ }
+
+ /**
+ * Not supported in composite.
+ * @return null
+ * @see org.osgi.framework.ServiceReference#getBundle()
+ */
+ public Bundle getBundle() {
+ return m_cm.getContext().getBundle();
+ }
+
+ /**
+ * Get the service registration for this reference.
+ * @return the service registration for this service reference.
+ */
+ public ServiceRegistrationImpl getServiceRegistration() {
+ return m_registration;
+ }
+
+
+ /**
+ * Get a property value.
+ * @param name : the key of the required property.
+ * @return the property value or null if no property for the given key.
+ * @see org.osgi.framework.ServiceReference#getProperty(java.lang.String)
+ */
+ public Object getProperty(String name) {
+ return m_registration.getProperty(name);
+ }
+
+ /**
+ * Get the String arrays of service property keys.
+ * @return : the list of property keys.
+ * @see org.osgi.framework.ServiceReference#getPropertyKeys()
+ */
+ public String[] getPropertyKeys() {
+ return m_registration.getPropertyKeys();
+ }
+
+ public Dictionary getProperties() {
+ return m_registration.getProperties();
+ }
+
+
+ /**
+ * Unsupported Operation inside composite.
+ * @return bundles using this reference.
+ * @see org.osgi.framework.ServiceReference#getUsingBundles()
+ */
+ public Bundle[] getUsingBundles() {
+ throw new UnsupportedOperationException("getUsingBundles is not supported in service context");
+ }
+
+ /**
+ * Check if the current service reference is assignable to the given bundle.
+ * @param arg0 : the bundle to check
+ * @param arg1 : the class name to check.
+ * @return true in the case of composite
+ * @see org.osgi.framework.ServiceReference#isAssignableTo(org.osgi.framework.Bundle, java.lang.String)
+ */
+ public boolean isAssignableTo(Bundle arg0, String arg1) {
+ return true;
+ }
+
+ /**
+ * Service Reference compare method.
+ * @param reference the service reference
+ * @return this methods is not yet supported, and throws an
+ * {@link UnsupportedOperationException}.
+ * @see org.osgi.framework.ServiceReference#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object reference) {
+
+ ServiceReference other = (ServiceReference) reference;
+
+ Long id = (Long) getProperty(Constants.SERVICE_ID);
+ Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
+
+ if (id.equals(otherId)) {
+ return 0; // same service
+ }
+
+ Integer rank = (Integer) getProperty(Constants.SERVICE_RANKING);
+ Integer otherRank = (Integer) other
+ .getProperty(Constants.SERVICE_RANKING);
+
+ // If no rank, then spec says it defaults to zero.
+ rank = (rank == null) ? new Integer(0) : rank;
+ otherRank = (otherRank == null) ? new Integer(0) : otherRank;
+
+ // Sort by rank in ascending order.
+ if (rank.compareTo(otherRank) < 0) {
+ return -1; // lower rank
+ } else if (rank.compareTo(otherRank) > 0) {
+ return 1; // higher rank
+ }
+
+ // If ranks are equal, then sort by service id in descending order.
+ return (id.compareTo(otherId) < 0) ? 1 : -1;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistrationImpl.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistrationImpl.java
new file mode 100644
index 0000000..0dc8dfb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistrationImpl.java
@@ -0,0 +1,272 @@
+/*
+ * 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.context;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Internal service registration implementation. This class is used for in the
+ * composition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceRegistrationImpl implements ServiceRegistration {
+
+ /**
+ * Service Registry.
+ */
+ private ServiceRegistry m_registry = null;
+
+ /**
+ * Interfaces associated with the service object.
+ */
+ private String[] m_classes = null;
+
+ /**
+ * Service Id associated with the service object.
+ */
+ private Long m_serviceId = null;
+
+ /**
+ * Service object.
+ */
+ private Object m_svcObj = null;
+
+ /**
+ * Service factory interface.
+ */
+ private ServiceFactory m_factory = null;
+
+ /**
+ * Associated property dictionary.
+ */
+ private Map m_propMap = null;
+
+ /**
+ * Re-usable service reference.
+ */
+ private ServiceReferenceImpl m_ref = null;
+
+ /**
+ * Property Keys List.
+ */
+ private List m_list = new ArrayList();
+
+ /**
+ * Constructor.
+ *
+ * @param registry : the service registry
+ * @param instance : component instance
+ * @param classes : published interfaces array
+ * @param serviceId : the unique service id
+ * @param svcObj : the service object or the service factory object
+ * @param dict : service properties
+ */
+ public ServiceRegistrationImpl(ServiceRegistry registry, ComponentInstance instance, String[] classes, Long serviceId, Object svcObj, Dictionary dict) {
+ m_registry = registry;
+ m_classes = classes;
+ m_serviceId = serviceId;
+ m_svcObj = svcObj;
+ if (m_svcObj instanceof ServiceFactory) { m_factory = (ServiceFactory) m_svcObj; }
+ initializeProperties(dict);
+
+ // This reference is the "standard" reference for this service and will
+ // always be returned by getReference().
+ // Since all reference to this service are supposed to be equal, we use
+ // the hash code of this reference for
+ // a references to this service in ServiceReference.
+ m_ref = new ServiceReferenceImpl(instance, this);
+ }
+
+ /**
+ * Check if the service registration still valid.
+ * @return true if the service registration is valid.
+ */
+ protected boolean isValid() {
+ return m_svcObj != null;
+ }
+
+ /**
+ * Get the service reference attached with this service registration.
+ * @return the service reference
+ * @see org.osgi.framework.ServiceRegistration#getReference()
+ */
+ public ServiceReference getReference() {
+ return m_ref;
+ }
+
+ /**
+ * Add properties to a service registration.
+ * @param dict : the properties to add
+ * @see org.osgi.framework.ServiceRegistration#setProperties(java.util.Dictionary)
+ */
+ public void setProperties(Dictionary dict) {
+ // Make sure registration is valid.
+ if (!isValid()) {
+ throw new IllegalStateException("The service registration is no longer valid.");
+ }
+ // Set the properties.
+ initializeProperties(dict);
+ // Tell registry about it.
+ m_registry.servicePropertiesModified(this);
+ }
+
+ /**
+ * Unregister the service.
+ * @see org.osgi.framework.ServiceRegistration#unregister()
+ */
+ public void unregister() {
+ if (m_svcObj == null) {
+ throw new IllegalStateException("Service already unregistered.");
+ } else {
+ m_registry.unregisterService(this);
+ m_svcObj = null;
+ m_factory = null;
+ }
+ }
+
+ /**
+ * Look for a property in the service properties.
+ * @param key : property key
+ * @return the object associated with the key or null if the key is not
+ * present.
+ */
+ protected Object getProperty(String key) {
+ return m_propMap.get(key);
+ }
+
+ /**
+ * Get the property keys.
+ * @return the property keys list.
+ */
+ protected String[] getPropertyKeys() {
+ synchronized (m_propMap) {
+ m_list.clear();
+ Iterator iterator = m_propMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ m_list.add(entry.getKey());
+ }
+ return (String[]) m_list.toArray(new String[m_list.size()]);
+ }
+ }
+
+ /**
+ * Gets the published properties.
+ * @return the dictionary containing each published properties.
+ */
+ protected Dictionary getProperties() {
+ synchronized (m_propMap) {
+ Dictionary dict = new Properties();
+ Iterator keys = m_propMap.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ dict.put(key, m_propMap.get(key));
+ }
+ return dict;
+ }
+ }
+
+ /**
+ * Get the service object.
+ * @return the service object. Call the service factory if needed.
+ */
+ protected Object getService() {
+ // If the service object is a service factory, then
+ // let it create the service object.
+ if (m_factory == null) {
+ return m_svcObj;
+ } else {
+ return getFactoryUnchecked();
+ }
+ }
+
+ /**
+ * Initialize properties.
+ * @param dict : service properties to publish.
+ */
+ private void initializeProperties(Dictionary dict) {
+ // Create a case insensitive map.
+ if (m_propMap == null) {
+ m_propMap = new StringMap(false);
+ } else {
+ m_propMap.clear();
+ }
+
+ if (dict != null) {
+ Enumeration keys = dict.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ m_propMap.put(key, dict.get(key));
+ }
+ }
+ // Add the framework assigned properties.
+ m_propMap.put(Constants.OBJECTCLASS, m_classes);
+ m_propMap.put(Constants.SERVICE_ID, m_serviceId);
+ }
+
+ /**
+ * Get a service object via a service factory.
+ * @return the service object via the service factory invocation.
+ */
+ private Object getFactoryUnchecked() {
+ return m_factory.getService(null, this);
+ }
+
+ /**
+ * Unget a service. (Internal Method)
+ *
+ * @param instance : component instance using the service.
+ * @param svcObj : the unget service object.
+ */
+ private void ungetFactoryUnchecked(ComponentInstance instance, Object svcObj) {
+ if (instance instanceof InstanceManager) {
+ m_factory.ungetService(((InstanceManager) instance).getContext().getBundle(), this, svcObj);
+ }
+
+ }
+
+ /**
+ * Unget a service.
+ *
+ * @param instance : component instance using the service.
+ * @param srvObj : the unget service object.
+ */
+ public void ungetService(ComponentInstance instance, Object srvObj) {
+ // If the service object is a service factory, then let is release the
+ // service object.
+ if (m_factory != null) {
+ ungetFactoryUnchecked(instance, srvObj);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java
new file mode 100644
index 0000000..81c1a7c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/ServiceRegistry.java
@@ -0,0 +1,346 @@
+/*
+ * 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.context;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Internal Service Registry. This class is used for in the composition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceRegistry {
+
+ /**
+ * Service Id index.
+ */
+ private long m_serviceId = 1L;
+
+ /**
+ * List of service listeners.
+ */
+ private List m_listeners = new ArrayList(); // ListenerInfo List
+
+ /**
+ * List of service registration.
+ */
+ private List m_regs = new ArrayList();
+
+ /**
+ * A "real" bundle context to create LDAP filter.
+ */
+ private BundleContext m_context; // BundleContext to create Filter
+
+ /**
+ * Registry logger.
+ */
+ private Logger m_logger;
+
+ /**
+ * Listener info structure.
+ */
+ private static class ListenerInfo {
+ /**
+ * Listener object.
+ */
+ private ServiceListener m_listener;
+ /**
+ * Filter associated with the filter.
+ */
+ private Filter m_filter;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context : bundle context.
+ */
+ public ServiceRegistry(BundleContext context) {
+ m_context = context;
+ m_logger = new Logger(m_context, "Registry logger " + m_context.getBundle().getBundleId());
+ }
+
+ /**
+ * Add a given service listener with no filter.
+ *
+ * @param arg0 : the service listener to add
+ */
+ public void addServiceListener(ServiceListener arg0) {
+ ListenerInfo info = new ListenerInfo();
+ info.m_listener = arg0;
+ info.m_filter = null;
+ m_listeners.add(info);
+ }
+
+ /**
+ * Unget a service.
+ *
+ * @param instance : instance releasing the service.
+ * @param ref : released reference.
+ * @return true if the unget success
+ */
+ public boolean ungetService(ComponentInstance instance, ServiceReference ref) {
+
+ ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+ if (reg.isValid()) {
+ reg.ungetService(instance, reg.getService());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Unregister a service listener.
+ *
+ * @param arg0 : the service listener to remove
+ */
+ public void removeServiceListener(ServiceListener arg0) {
+ m_listeners.remove(arg0);
+ }
+
+ /**
+ * Register a service.
+ *
+ * @param instance : provider instance.
+ * @param clazz : provided interface.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
+ * @return the created service registration.
+ */
+ public ServiceRegistration registerService(ComponentInstance instance, String clazz, Object svcObj, Dictionary dict) {
+ synchronized (m_regs) {
+ ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, new String[] { clazz }, new Long(m_serviceId++), svcObj, dict);
+ m_regs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
+ }
+ }
+
+ /**
+ * Register a service.
+ *
+ * @param instance : provider instance.
+ * @param clazzes : provided interfaces.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
+ * @return the created service registration.
+ */
+ public ServiceRegistration registerService(ComponentInstance instance, String[] clazzes, Object svcObj, Dictionary dict) {
+ synchronized (m_regs) {
+ ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, instance, clazzes, new Long(m_serviceId++), svcObj, dict);
+ m_regs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
+ }
+ }
+
+ /**
+ * Dispatch a service event.
+ * @param event : the service to dispatch
+ */
+ private void fireServiceChanged(ServiceEvent event) {
+ synchronized (m_listeners) {
+ // Iterate on the service listener list to notify service listener
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ListenerInfo info = (ListenerInfo) m_listeners.get(i);
+ ServiceReference ref = event.getServiceReference();
+ if (info.m_filter == null) {
+ info.m_listener.serviceChanged(event);
+ }
+ Dictionary props = ((ServiceReferenceImpl) ref).getProperties();
+ if (info.m_filter != null && info.m_filter.match(props)) {
+ info.m_listener.serviceChanged(event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get available (and accessible) service references.
+ *
+ * @param className : required interface
+ * @param expr : LDAP filter
+ * @return : the list of available service references.
+ * @throws InvalidSyntaxException
+ * occurs when the LDAP filter is malformed.
+ */
+ public ServiceReference[] getServiceReferences(String className, String expr) throws InvalidSyntaxException {
+ synchronized (m_regs) {
+ // Define filter if expression is not null.
+ Filter filter = null;
+ if (expr != null) {
+ filter = m_context.createFilter(expr);
+ }
+
+ List refs = new ArrayList();
+
+ for (int i = 0; i < m_regs.size(); i++) {
+ ServiceRegistrationImpl reg = (ServiceRegistrationImpl) m_regs.get(i);
+ // Determine if the registered services matches the search
+ // criteria.
+ boolean matched = false;
+
+ // If className is null, then look at filter only.
+ if ((className == null) && ((filter == null) || filter.match(reg.getProperties()))) {
+ matched = true;
+ } else if (className != null) {
+ // If className is not null, then first match the
+ // objectClass property before looking at the
+ // filter.
+ Dictionary props = ((ServiceRegistrationImpl) reg).getProperties();
+ String[] objectClass = (String[]) props.get(Constants.OBJECTCLASS);
+ for (int classIdx = 0; classIdx < objectClass.length; classIdx++) {
+ if (objectClass[classIdx].equals(className) && ((filter == null) || filter.match(props))) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ // Add reference if it was a match.
+ if (matched) {
+ refs.add(reg.getReference());
+ }
+ }
+
+ if (! refs.isEmpty()) {
+ return (ServiceReference[]) refs.toArray(new ServiceReference[refs.size()]);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Look for a service reference.
+ *
+ * @param clazz : required interface.
+ * @return the first available provider or null if none available.
+ */
+ public ServiceReference getServiceReference(String clazz) {
+ synchronized (m_regs) {
+ try {
+ ServiceReference[] refs = getServiceReferences(clazz, null);
+ if (refs != null) {
+ return refs[0];
+ } // If the refs != null we are sure that it exists one reference or more.
+ } catch (InvalidSyntaxException ex) {
+ // Cannot happen : null filter.
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Get a service object.
+ * @param instance : component instance requiring the service.
+ * @param ref : the required reference.
+ * @return the service object.
+ */
+ public Object getService(ComponentInstance instance, ServiceReference ref) {
+ synchronized (m_regs) {
+ // Look for the service registration for this ref
+ ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+ if (reg.isValid()) {
+ // Delegate the service providing to the service registration
+ return reg.getService();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Get all service references consistent with the given interface and
+ * filter.
+ * @param clazz : the required interface.
+ * @param filter : the LDAP filter.
+ * @return the list of all service reference or null if none available.
+ * @throws InvalidSyntaxException occurs when the LDAP filter is malformed.
+ */
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ synchronized (m_regs) {
+ // Can delegate on getServiceReference, indeed their is no test on
+ // the "modularity" conflict.
+ return getServiceReferences(clazz, filter);
+ }
+ }
+
+ /**
+ * Add a service listener with a filter.
+ * @param listener : the service listener to add
+ * @param filter : LDAP filter
+ */
+ public void addServiceListener(ServiceListener listener, String filter) {
+ // If the filter is null, subscribe with no filter.
+ if (filter == null) {
+ addServiceListener(listener);
+ return;
+ }
+
+ try {
+ ListenerInfo info = new ListenerInfo();
+ info.m_listener = listener;
+ info.m_filter = m_context.createFilter(filter);
+ m_listeners.add(info);
+ } catch (InvalidSyntaxException ex) {
+ m_logger.log(Logger.ERROR, ex.getMessage(), ex);
+ }
+
+ }
+
+ /**
+ * Dispatch a service properties modified event.
+ * @param reg : the implicated service registration.
+ */
+ public void servicePropertiesModified(ServiceRegistrationImpl reg) {
+ fireServiceChanged(new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()));
+ }
+
+ /**
+ * Unregister a service.
+ * @param reg : the service registration to unregister
+ */
+ public void unregisterService(ServiceRegistrationImpl reg) {
+ m_regs.remove(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+ }
+
+ /**
+ * Reset the service registry.
+ */
+ public void reset() {
+ m_serviceId = 1L;
+ m_listeners = new ArrayList();
+ m_regs = new ArrayList();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/StringMap.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/StringMap.java
new file mode 100644
index 0000000..c189f38
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/context/StringMap.java
@@ -0,0 +1,148 @@
+/*
+ * 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.context;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Simple utility class that creates a map for string-based keys by extending
+ * <tt>TreeMap</tt>. This map can be set to use case-sensitive or
+ * case-insensitive comparison when searching for the key. Any keys put into
+ * this map will be converted to a <tt>String</tt> using the
+ * <tt>toString()</tt> method, since it is only intended to compare strings.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StringMap extends TreeMap {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = 6948801857034259744L;
+
+ /**
+ * Constructor.
+ */
+ public StringMap() {
+ this(true);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param caseSensitive : fix if the map if case sensitive or not.
+ */
+ public StringMap(boolean caseSensitive) {
+ super(new StringComparator(caseSensitive));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param map : initial properties.
+ * @param caseSensitive : fix if the map if case sensitive or not.
+ */
+ public StringMap(Map map, boolean caseSensitive) {
+ this(caseSensitive);
+ putAll(map);
+ }
+
+ /**
+ * Put a record in the map.
+ * @param key : key
+ * @param value : value
+ * @return an object.
+ * @see java.util.TreeMap#put(Object, Object)
+ */
+ public Object put(Object key, Object value) {
+ return super.put(key.toString(), value);
+ }
+
+ /**
+ * Check if the map is case-sensitive.
+ * @return true if the map is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return ((StringComparator) comparator()).isCaseSensitive();
+ }
+
+ /**
+ * Set the case sensitivity.
+ *
+ * @param flag : the new case sensitivity.
+ */
+ public void setCaseSensitive(boolean flag) {
+ ((StringComparator) comparator()).setCaseSensitive(flag);
+ }
+
+ private static class StringComparator implements Comparator, Serializable {
+ /**
+ * Id.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Is the map case sensitive?
+ */
+ private boolean m_isCaseSensitive = true;
+
+ /**
+ * Constructor.
+ *
+ * @param flag : true to enable the case sensitivity.
+ */
+ public StringComparator(boolean flag) {
+ m_isCaseSensitive = flag;
+ }
+
+ /**
+ * Compare to object.
+ * @param object1 : first object to compare
+ * @param object2 : second object to compare
+ * @return the comparison result
+ * @see java.util.Comparator#compare(Object, Object)
+ */
+ public int compare(Object object1, Object object2) {
+ if (m_isCaseSensitive) {
+ return object1.toString().compareTo(object2.toString());
+ } else {
+ return object1.toString().compareToIgnoreCase(object2.toString());
+ }
+ }
+
+ /**
+ * Check if the comparator is case sensitive.
+ * @return true if the map is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return m_isCaseSensitive;
+ }
+
+ /**
+ * Set the case sensitivity.
+ *
+ * @param flag : true to enable the case sensitivity
+ */
+ public void setCaseSensitive(boolean flag) {
+ m_isCaseSensitive = flag;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ComparatorBasedServiceRankingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ComparatorBasedServiceRankingInterceptor.java
new file mode 100644
index 0000000..630190c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ComparatorBasedServiceRankingInterceptor.java
@@ -0,0 +1,65 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A comparator based version of the ranking interceptor.
+ */
+public class ComparatorBasedServiceRankingInterceptor implements ServiceRankingInterceptor {
+
+ private final Comparator<ServiceReference> m_comparator;
+
+ public ComparatorBasedServiceRankingInterceptor(Comparator<ServiceReference> cmp) {
+ this.m_comparator = cmp;
+ }
+
+
+ public void open(DependencyModel dependency) { }
+
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ List<ServiceReference> copy = new ArrayList<ServiceReference>(matching);
+ Collections.sort(copy, m_comparator);
+ return copy;
+ }
+
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching,
+ ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public void close(DependencyModel dependency) { }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/DependencyProperties.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/DependencyProperties.java
new file mode 100644
index 0000000..ecf2249
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/DependencyProperties.java
@@ -0,0 +1,109 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.Log;
+import org.osgi.framework.*;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * Builds the properties used to checks if an interceptor matches a specific dependency.
+ */
+public class DependencyProperties {
+
+ //TODO Externalize and use constants
+ // TODO Cache dependency properties.
+
+ public static Dictionary<String, ?> getDependencyProperties(DependencyModel dependency) {
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+
+ // Instance, and Factory and Bundle (name, symbolic name, version)
+ properties.put(Factory.INSTANCE_NAME_PROPERTY, dependency.getComponentInstance().getInstanceName());
+ properties.put("instance.state", dependency.getComponentInstance().getState());
+ properties.put("factory.name", dependency.getComponentInstance().getFactory().getFactoryName());
+ final Bundle bundle = dependency.getBundleContext().getBundle();
+ properties.put("bundle.symbolicName", bundle.getSymbolicName());
+ if (bundle.getVersion() != null) {
+ properties.put("bundle.version", bundle.getVersion().toString());
+ }
+
+ // Dependency specification, and id
+ final Class specification = dependency.getSpecification();
+ properties.put("dependency.specification", specification.getName());
+ properties.put("dependency.id", dependency.getId());
+ properties.put("dependency.state", dependency.getState());
+
+ // We also provide the objectclass property, and to be compliant with the osgi specification,
+ // all interfaces are collected to this array.
+ List<String> classes = new ArrayList<String>();
+ classes.add(specification.getName());
+ for (Class clazz : specification.getInterfaces()) {
+ classes.add(clazz.getName());
+ }
+ properties.put(Constants.OBJECTCLASS, classes.toArray(new String[classes.size()]));
+
+ return properties;
+ }
+
+
+ /**
+ * Checks that the 'target' property of the service reference matches the dependency.
+ * @param reference the reference
+ * @param dependency the dependency
+ * @param context a bundle context used to build the filter
+ * @return {@literal true} if the target's property of reference matches the dependency.
+ */
+ public static boolean match(ServiceReference reference, DependencyModel dependency, BundleContext context) {
+ Object v = reference.getProperty(ServiceTrackingInterceptor.TARGET_PROPERTY);
+ Filter filter = null;
+ if (v == null) {
+ return false; // Invalid interceptor
+ }
+ if (v instanceof Filter) {
+ filter = (Filter) v;
+ } else if (v instanceof String) {
+ try {
+ filter = context.createFilter((String) v);
+ } catch (InvalidSyntaxException e) {
+ dependency.getComponentInstance().getFactory().getLogger().log(Log.ERROR,
+ "Cannot build filter from the target property : " + v, e);
+ }
+ }
+
+ if (filter == null) {
+ return false; // Invalid interceptor.
+ }
+
+ Dictionary<String, ?> properties = getDependencyProperties(dependency);
+
+ return filter.match(properties);
+ }
+
+ public static boolean match(ServiceReference reference, DependencyModel dependency) {
+ return match(reference, dependency, dependency.getBundleContext());
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/EmptyBasedServiceRankingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/EmptyBasedServiceRankingInterceptor.java
new file mode 100644
index 0000000..82dc44a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/EmptyBasedServiceRankingInterceptor.java
@@ -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.felix.ipojo.dependency.impl;
+
+import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * An empty version of the ranking interceptor.
+ */
+public class EmptyBasedServiceRankingInterceptor implements ServiceRankingInterceptor {
+
+ public void open(DependencyModel dependency) { }
+
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ return matching;
+ }
+
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching,
+ ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public void close(DependencyModel dependency) { }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/FilterBasedServiceTrackingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/FilterBasedServiceTrackingInterceptor.java
new file mode 100644
index 0000000..4950e65
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/FilterBasedServiceTrackingInterceptor.java
@@ -0,0 +1,63 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An implementation of the service tracking interceptor using a filter.
+ */
+public class FilterBasedServiceTrackingInterceptor implements ServiceTrackingInterceptor {
+
+ private final Filter m_filter;
+
+ public FilterBasedServiceTrackingInterceptor(Filter filter) {
+ m_filter = filter;
+ }
+
+ public void open(DependencyModel dependency) {
+
+ }
+
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context, TransformedServiceReference<S> ref) {
+ if (ServiceReferenceUtils.match(m_filter, ref) && dependency.match(ref)) {
+ return ref;
+ } else {
+ return null;
+ }
+ }
+
+ public void close(DependencyModel dependency) {
+
+ }
+
+ public <S> S getService(DependencyModel dependency, S service, ServiceReference<S> reference) {
+ return service;
+ }
+
+ public void ungetService(DependencyModel dependency, boolean noMoreUsage, ServiceReference reference) {
+
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java
new file mode 100644
index 0000000..7bba1cc
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceManager.java
@@ -0,0 +1,982 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceBindingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceRankingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.apache.felix.ipojo.util.*;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+import static org.apache.felix.ipojo.util.DependencyModel.DependencyEventType;
+import static org.apache.felix.ipojo.util.DependencyModel.DependencyEventType.ARRIVAL;
+import static org.apache.felix.ipojo.util.DependencyModel.DependencyEventType.DEPARTURE;
+import static org.apache.felix.ipojo.util.DependencyModel.DependencyEventType.MODIFIED;
+
+/**
+ * This class is handling the transformations between the base service set and the selected service set.
+ * It handles the matching services and the selected service set.
+ * As this class is tied to the dependency model, it reuses the same locks objects.
+ */
+public class ServiceReferenceManager implements TrackerCustomizer {
+
+ /**
+ * The dependency.
+ */
+ private final DependencyModel m_dependency;
+ /**
+ * The list of all matching service references. This list is a
+ * subset of tracked references. This set is computed according
+ * to the filter and the {@link DependencyModel#match(ServiceReference)} method.
+ */
+ private final Map<ServiceReference, TransformedServiceReference> m_matchingReferences = new
+ LinkedHashMap<ServiceReference, TransformedServiceReference>();
+ /**
+ * The comparator to sort service references.
+ */
+ private Comparator<ServiceReference> m_comparator;
+ /**
+ * The LDAP filter object selecting service references
+ * from the set of providers providing the required specification.
+ */
+ private Filter m_filter;
+ /**
+ * The list of selected service references.
+ */
+ private List<? extends ServiceReference> m_selectedReferences = new ArrayList<ServiceReference>();
+ /**
+ * The service ranking interceptor.
+ */
+ private ServiceRankingInterceptor m_rankingInterceptor;
+ /**
+ * Service Ranking Interceptor trackers.
+ */
+ private Tracker m_rankingInterceptorTracker;
+
+ /**
+ * Service Tracking Interceptor trackers.
+ */
+ private Tracker m_trackingInterceptorTracker;
+
+ /**
+ * Service Binding Interceptor trackers.
+ */
+ private Tracker m_bindingInterceptorTracker;
+
+ /**
+ * The set of tracking interceptors.
+ * TODO this set should be sorted according to the OSGi ranking policy.
+ * The filter is always the last interceptor.
+ */
+ private LinkedList<ServiceTrackingInterceptor> m_trackingInterceptors = new
+ LinkedList<ServiceTrackingInterceptor>();
+
+ /**
+ * The set of binding interceptors.
+ * TODO this set should be sorted according to the OSGi ranking policy.
+ */
+ private LinkedList<ServiceBindingInterceptor> m_bindingInterceptors = new
+ LinkedList<ServiceBindingInterceptor>();
+
+ /**
+ * Creates the service reference manager.
+ *
+ * @param dep the dependency
+ * @param filter the filter
+ * @param comparator the comparator
+ */
+ public ServiceReferenceManager(DependencyModel dep, Filter filter, Comparator<ServiceReference> comparator) {
+ m_dependency = dep;
+ m_filter = filter;
+ // The Filter based service tracking interceptor needs to be created every time even if the filter is null.
+ // This arises from the potential re-implementation of the match method in the dependency implementation.
+ // It must be the last interceptor as the chain ends on the filter matching. (FELIX-4199)
+ m_trackingInterceptors.addLast(new FilterBasedServiceTrackingInterceptor(m_filter));
+
+ if (comparator != null) {
+ m_comparator = comparator;
+ m_rankingInterceptor = new ComparatorBasedServiceRankingInterceptor(comparator);
+ } else {
+ m_rankingInterceptor = new EmptyBasedServiceRankingInterceptor();
+ }
+ }
+
+ public void open() {
+ // The opening order matters, first binding, then ranking and finally tracking.
+ m_bindingInterceptorTracker = new Tracker(m_dependency.getBundleContext(),
+ ServiceBindingInterceptor.class.getName(),
+ new TrackerCustomizer() {
+
+ public boolean addingService(ServiceReference reference) {
+ return DependencyProperties.match(reference, m_dependency);
+ }
+
+ public void addedService(ServiceReference reference) {
+ ServiceBindingInterceptor interceptor = (ServiceBindingInterceptor) m_bindingInterceptorTracker
+ .getService(reference);
+ if (interceptor != null) {
+ addBindingInterceptor(interceptor);
+ } else {
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Log.ERROR,
+ "Cannot retrieve the interceptor object from service reference " + reference
+ .getProperty(Constants.SERVICE_ID) + " - " + reference.getProperty
+ (Factory.INSTANCE_NAME_PROPERTY));
+ }
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Not supported.
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ if (service != null && service instanceof ServiceBindingInterceptor &&
+ m_bindingInterceptors.contains(service)
+ ) {
+ removeBindingInterceptor((ServiceBindingInterceptor) service);
+ }
+ }
+ }
+ );
+ m_bindingInterceptorTracker.open();
+
+ // Initialize the service interceptor tracker.
+ m_rankingInterceptorTracker = new Tracker(m_dependency.getBundleContext(), ServiceRankingInterceptor.class.getName(),
+ new TrackerCustomizer() {
+
+ public boolean addingService(ServiceReference reference) {
+ return DependencyProperties.match(reference, m_dependency);
+ }
+
+ public void addedService(ServiceReference reference) {
+ ServiceRankingInterceptor interceptor = (ServiceRankingInterceptor) m_rankingInterceptorTracker
+ .getService(reference);
+ if (interceptor != null) {
+ setRankingInterceptor(interceptor);
+ } else {
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Log.ERROR,
+ "Cannot retrieve the interceptor object from service reference " + reference
+ .getProperty(Constants.SERVICE_ID) + " - " + reference.getProperty
+ (Factory.INSTANCE_NAME_PROPERTY));
+ }
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Not supported yet.
+ // TODO it would be nice to support the modification of the interceptor TARGET property.
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ if (service == m_rankingInterceptor) {
+ m_rankingInterceptor.close(m_dependency);
+ // Do we have another one ?
+ ServiceReference anotherReference = m_rankingInterceptorTracker.getServiceReference();
+ if (anotherReference != null) {
+ ServiceRankingInterceptor interceptor = (ServiceRankingInterceptor) m_rankingInterceptorTracker
+ .getService(anotherReference);
+ if (interceptor != null) setRankingInterceptor(interceptor);
+ } else if (m_comparator != null) {
+ // If we have a comparator, we restore the comparator.
+ setComparator(m_comparator);
+ } else {
+ // If we have neither comparator nor interceptor use an empty interceptor.
+ setRankingInterceptor(new EmptyBasedServiceRankingInterceptor());
+ }
+ }
+ }
+ });
+ m_rankingInterceptorTracker.open();
+
+ m_trackingInterceptorTracker = new Tracker(m_dependency.getBundleContext(),
+ ServiceTrackingInterceptor.class.getName(),
+ new TrackerCustomizer() {
+
+ public boolean addingService(ServiceReference reference) {
+ return DependencyProperties.match(reference, m_dependency);
+ }
+
+ public void addedService(ServiceReference reference) {
+ ServiceTrackingInterceptor interceptor = (ServiceTrackingInterceptor) m_trackingInterceptorTracker
+ .getService(reference);
+
+ if (interceptor != null) {
+ addTrackingInterceptor(interceptor);
+ } else {
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Log.ERROR,
+ "Cannot retrieve the interceptor object from service reference " + reference
+ .getProperty(Constants.SERVICE_ID) + " - " + reference.getProperty
+ (Factory.INSTANCE_NAME_PROPERTY));
+ }
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Not supported yet.
+ // TODO it would be nice to support the modification of the interceptor TARGET property.
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ if (service != null && service instanceof ServiceTrackingInterceptor &&
+ m_trackingInterceptors.contains(service)
+ ) {
+ removeTrackingInterceptor((ServiceTrackingInterceptor) service);
+ }
+ }
+ });
+
+ m_trackingInterceptorTracker.open();
+ }
+
+ private void addTrackingInterceptor(ServiceTrackingInterceptor interceptor) {
+ // A new interceptor arrives. Insert it at the beginning of the list.
+ ChangeSet changeset;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_trackingInterceptors.addFirst(interceptor);
+ interceptor.open(m_dependency);
+ changeset = computeChangesInMatchingServices();
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ m_dependency.onChange(changeset);
+ }
+
+ private void removeTrackingInterceptor(ServiceTrackingInterceptor interceptor) {
+ ChangeSet changeset;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_trackingInterceptors.remove(interceptor);
+ interceptor.close(m_dependency);
+ changeset = computeChangesInMatchingServices();
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ m_dependency.onChange(changeset);
+ }
+
+ private void addBindingInterceptor(ServiceBindingInterceptor interceptor) {
+ // A new interceptor arrives, open it.
+ // Binding interceptor cannot modify existing bindings.
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_bindingInterceptors.add(interceptor);
+ interceptor.open(m_dependency);
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ }
+
+ private void removeBindingInterceptor(ServiceBindingInterceptor interceptor) {
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_bindingInterceptors.remove(interceptor);
+ interceptor.close(m_dependency);
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ }
+
+ public Object weavingServiceBinding(DependencyModel.ServiceBindingHolder sbh) {
+ Object svc = sbh.service;
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ for (ServiceBindingInterceptor interceptor : m_bindingInterceptors) {
+ // Interceptor are not allowed to return null.
+ svc = interceptor.getService(m_dependency, sbh.reference, svc);
+ }
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ return svc;
+ }
+
+ public void unweavingServiceBinding(DependencyModel.ServiceBindingHolder sbh) {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ for (ServiceBindingInterceptor interceptor : m_bindingInterceptors) {
+ interceptor.ungetService(m_dependency, sbh.reference);
+ }
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ private ChangeSet computeChangesInMatchingServices() {
+ if (m_dependency.getTracker() == null || m_dependency.getTracker().getServiceReferences() == null) {
+ // Tracker closed, no problem
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Logger.DEBUG,
+ "Tracker closed when recomputing dependency " + m_dependency.getId());
+ return new ChangeSet(Collections.<ServiceReference>emptyList(),
+ Collections.<ServiceReference>emptyList(),
+ Collections.<ServiceReference>emptyList(),
+ null,
+ null,
+ null,
+ null);
+ }
+ // The set of interceptor has changed.
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ // The tracker is open, we must recheck all services.
+ ServiceReference oldBest = getFirstService();
+ // Recompute the matching services.
+ m_matchingReferences.clear();
+ final List<ServiceReference> serviceReferencesList = m_dependency.getTracker().getServiceReferencesList();
+ if (serviceReferencesList != null) {
+ for (ServiceReference reference : serviceReferencesList) {
+ TransformedServiceReference ref = new TransformedServiceReferenceImpl(reference);
+ ref = accept(ref);
+ if (ref != null) {
+ m_matchingReferences.put(reference, ref);
+ }
+ }
+ }
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Logger.DEBUG,
+ "Matching services have been recomputed: " + ServiceReferenceUtils.toString(m_matchingReferences.values()));
+
+
+ // We have the new matching set.
+ List<ServiceReference> beforeRanking = getSelectedServices();
+
+ final List<ServiceReference> allServices = getMatchingServices();
+ List<ServiceReference> references;
+ if (allServices.isEmpty()) {
+ references = Collections.emptyList();
+ } else {
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Logger.DEBUG,
+ "iPOJO >> Calling getServiceReferences on the interceptor " + m_rankingInterceptor);
+ references = m_rankingInterceptor.getServiceReferences(m_dependency, allServices);
+ }
+
+ RankingResult result = computeDifferences(beforeRanking, references);
+ m_selectedReferences = result.selected;
+
+ ServiceReference newFirst = getFirstService();
+ ServiceReference modified = null;
+ if (ServiceReferenceUtils.haveSameServiceId(oldBest, newFirst) && ServiceReferenceUtils
+ .haveSameProperties(oldBest, newFirst)) {
+ modified = newFirst;
+ }
+ return new ChangeSet(getSelectedServices(), result.departures, result.arrivals, oldBest, getFirstService(),
+ null, modified);
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ }
+
+ public List<ServiceReference> getMatchingServices() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return new ArrayList<ServiceReference>(m_matchingReferences.values());
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public List<ServiceReference> getSelectedServices() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return new ArrayList<ServiceReference>(m_selectedReferences);
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public ServiceReference getFirstService() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ if (m_selectedReferences.isEmpty()) {
+ return null;
+ }
+ return m_selectedReferences.get(0);
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public boolean contains(ServiceReference ref) {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return m_selectedReferences.contains(ref);
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public void reset() {
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_rankingInterceptor.close(m_dependency);
+ for (ServiceTrackingInterceptor interceptor : m_trackingInterceptors) {
+ interceptor.close(m_dependency);
+ }
+ m_trackingInterceptors.clear();
+ m_matchingReferences.clear();
+ m_selectedReferences = new ArrayList<TransformedServiceReference>();
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+
+ }
+
+ public boolean addingService(ServiceReference reference) {
+ // We accept all service references except if we are frozen or broken. In these case, just ignore everything.
+
+ // We are doing two tests, we must get the read lock
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return !(m_dependency.getState() == DependencyModel.BROKEN || m_dependency.isFrozen());
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Checks if the given reference is accepted.
+ * This method is called when holding the write lock on the dependency.
+ *
+ * @param reference the reference
+ * @param <S> the service interface
+ * @return the transformed reference, null if rejected
+ */
+ private <S> TransformedServiceReference<S> accept(TransformedServiceReference<S> reference) {
+ TransformedServiceReference<S> accumulator = reference;
+ for (ServiceTrackingInterceptor interceptor : m_trackingInterceptors) {
+ TransformedServiceReference<S> accepted = interceptor.accept(m_dependency,
+ m_dependency.getBundleContext(), accumulator);
+ if (accepted != null) {
+ accumulator = accepted;
+ } else {
+ // refused by an interceptor
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Log.INFO,
+ "The service reference " + reference.getProperty(Constants.SERVICE_ID) + " was rejected by " +
+ "interceptor " + interceptor);
+ return null;
+ }
+ }
+
+ return accumulator;
+ }
+
+ public void addedService(ServiceReference reference) {
+ // A service was added to the tracker.
+
+ // First, check is the tracking interceptors are accepting it.
+ // The transformed reference is creates and check outside of the protected region.
+ TransformedServiceReference ref = new TransformedServiceReferenceImpl(reference);
+
+ boolean match;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ ref = accept(ref);
+ if (ref != null) {
+ m_matchingReferences.put(reference, ref);
+ }
+ match = ref != null;
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+
+ if (match) {
+ // Callback invoked outside of locks.
+ // The called method is taking the write lock anyway.
+ onNewMatchingService(ref);
+ m_dependency.notifyListeners(ARRIVAL, ref, null);
+ }
+ }
+
+ private void onNewMatchingService(TransformedServiceReference reference) {
+ ServiceReference oldFirst;
+ RankingResult result;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ // We store the currently 'first' service reference.
+ oldFirst = getFirstService();
+
+ // We apply our ranking strategy.
+ result = applyRankingOnArrival(reference);
+ // Set the selected services.
+ m_selectedReferences = result.selected;
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ // Fire the event (outside from the synchronized region)
+ fireUpdate(getSelectedServices(), result.departures, result.arrivals, oldFirst,
+ getFirstService(), null, null);
+ }
+
+ private void onModificationOfAMatchingService(TransformedServiceReference reference, Object service) {
+ ServiceReference oldFirst;
+ RankingResult result;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ // We store the currently 'first' service reference.
+ oldFirst = getFirstService();
+
+ // We apply our ranking strategy.
+ result = applyRankingOnModification(reference);
+ // Set the selected services.
+ m_selectedReferences = result.selected;
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ // Fire the event (outside from the synchronized region)
+ fireUpdate(getSelectedServices(), result.departures, result.arrivals, oldFirst,
+ getFirstService(), service, reference);
+ }
+
+ private RankingResult applyRankingOnModification(ServiceReference reference) {
+ // TODO we are holding the lock here.
+ List<ServiceReference> beforeRanking = getSelectedServices();
+ List<ServiceReference> references = m_rankingInterceptor.onServiceModified(m_dependency, getMatchingServices(),
+ reference);
+ return computeDifferences(beforeRanking, references);
+ }
+
+ private void fireUpdate(List<ServiceReference> selectedServices, List<ServiceReference> departures,
+ List<ServiceReference> arrivals, ServiceReference oldFirst,
+ ServiceReference firstService, Object service, ServiceReference modified) {
+ ChangeSet set = new ChangeSet(selectedServices, departures, arrivals, oldFirst, firstService, service, modified);
+ m_dependency.onChange(set);
+ }
+
+ private RankingResult applyRankingOnArrival(ServiceReference ref) {
+ // TODO we are holding the lock here.
+ List<ServiceReference> beforeRanking = getSelectedServices();
+ List<ServiceReference> references = m_rankingInterceptor.onServiceArrival(m_dependency, getMatchingServices(),
+ ref);
+ // compute the differences
+ return computeDifferences(beforeRanking, references);
+
+ }
+
+ private RankingResult applyRankingOnDeparture(ServiceReference ref) {
+ // TODO we are holding the lock here.
+ List<ServiceReference> beforeRanking = getSelectedServices();
+ List<ServiceReference> references = m_rankingInterceptor.onServiceDeparture(m_dependency, getMatchingServices(),
+ ref);
+ return computeDifferences(beforeRanking, references);
+ }
+
+ private RankingResult computeDifferences(List<ServiceReference> beforeRanking, List<ServiceReference> ranked) {
+ // compute the differences
+ List<ServiceReference> departures = new ArrayList<ServiceReference>();
+ List<ServiceReference> arrivals = new ArrayList<ServiceReference>();
+ // All references that are no more in the set are considered as leaving services.
+ for (ServiceReference old : beforeRanking) {
+ if (!ServiceReferenceUtils.containsReferenceById(ranked, old)) {
+ departures.add(old);
+ }
+ }
+ // All references that are in `references` but not in `beforeRanking` are new services
+ for (ServiceReference newRef : ranked) {
+ if (!ServiceReferenceUtils.containsReferenceById(beforeRanking, newRef)) {
+ arrivals.add(newRef);
+ }
+ }
+
+ return new RankingResult(departures, arrivals, ranked);
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ // We are handling a modified event, we have three case to handle
+ // 1) the service was matching and does not match anymore -> it's a departure.
+ // 2) the service was not matching and matches -> it's an arrival
+ // 3) the service was matching and still matches -> it's a modification.
+
+ // The dependency event to send
+ DependencyEventType eventType = null;
+ ServiceReference<?> eventRef = null;
+
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+
+ if (m_matchingReferences.containsKey(reference)) {
+ // do we still accept the reference
+ TransformedServiceReference initial = m_matchingReferences.get(reference);
+ TransformedServiceReference accepted = new TransformedServiceReferenceImpl(reference);
+ accepted = accept(accepted);
+ if (accepted == null) {
+ // case 1
+ m_matchingReferences.remove(reference);
+ onDepartureOfAMatchingService(initial, service);
+ eventType = DEPARTURE;
+ eventRef = initial;
+ } else {
+ // Do we have a real change
+ if (!ServiceReferenceUtils.haveSameProperties(initial, accepted)) {
+ // case 3
+ m_matchingReferences.put(reference, accepted);
+ onModificationOfAMatchingService(accepted, service);
+ eventType = MODIFIED;
+ eventRef = accepted;
+ }
+ }
+ } else {
+ // Base does not contain the service, let's try to add it.
+ TransformedServiceReference transformed = new TransformedServiceReferenceImpl(reference);
+ transformed = accept(transformed);
+ if (transformed != null) {
+ // case 2
+ m_matchingReferences.put(reference, transformed);
+ onNewMatchingService(transformed);
+ eventType = ARRIVAL;
+ eventRef = transformed;
+ }
+ }
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+
+ if (eventType != null) {
+ m_dependency.notifyListeners(eventType, eventRef, service);
+ }
+ }
+
+ public void onDepartureOfAMatchingService(TransformedServiceReference reference, Object service) {
+ ServiceReference oldFirst;
+ RankingResult result = null;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ // We store the currently 'first' service reference.
+ oldFirst = getFirstService();
+ // We apply our ranking strategy.
+ result = applyRankingOnDeparture(reference);
+ // Set the selected services.
+ m_selectedReferences = result.selected;
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ // Fire the event (outside from the synchronized region)
+ fireUpdate(getSelectedServices(), result.departures, result.arrivals, oldFirst,
+ getFirstService(), service, null);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ // A service is leaving
+ // 1 - the service was in the matching set => real departure
+ // 2 - the service was not in the matching set => nothing do do.
+
+ TransformedServiceReference initial = null;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ initial = m_matchingReferences.remove(reference);
+ if (initial != null) {
+ // Case 1
+ onDepartureOfAMatchingService(initial, service);
+ }
+ // else case 2.
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+
+ // Call the listeners outside the locked region.
+ if (initial != null) {
+ m_dependency.notifyListeners(DEPARTURE, initial, service);
+ }
+
+ }
+
+ /**
+ * A new filter is set.
+ * We have to recompute the set of matching services.
+ *
+ * @param filter the new filter
+ * @param tracker the tracker
+ */
+ public ChangeSet setFilter(Filter filter, Tracker tracker) {
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_filter = filter;
+
+ if (!m_trackingInterceptors.isEmpty()) {
+ ServiceTrackingInterceptor interceptor = m_trackingInterceptors.getLast();
+ if (interceptor != null && interceptor instanceof FilterBasedServiceTrackingInterceptor) {
+ // Remove it first.
+ m_trackingInterceptors.removeLast();
+ }
+ }
+
+ if (m_filter != null) {
+ // Add the new one.
+ ServiceTrackingInterceptor newInterceptor = new FilterBasedServiceTrackingInterceptor(m_filter);
+ m_trackingInterceptors.addLast(newInterceptor);
+ }
+
+ if (tracker == null) {
+ // Tracker closed, no problem
+ return new ChangeSet(Collections.<ServiceReference>emptyList(),
+ Collections.<ServiceReference>emptyList(),
+ Collections.<ServiceReference>emptyList(),
+ null,
+ null,
+ null,
+ null);
+ } else {
+ // The tracker is open, we must recheck all services.
+ ServiceReference oldBest = getFirstService();
+
+ // Recompute the matching services.
+ m_matchingReferences.clear();
+ final List<ServiceReference> serviceReferencesList = tracker.getServiceReferencesList();
+ if (serviceReferencesList != null) {
+ for (ServiceReference reference : serviceReferencesList) {
+ TransformedServiceReference ref = new TransformedServiceReferenceImpl(reference);
+ ref = accept(ref);
+ if (ref != null) {
+ m_matchingReferences.put(reference, ref);
+ }
+ }
+ }
+
+ // We have the new matching set.
+
+ List<ServiceReference> beforeRanking = getSelectedServices();
+
+ final List<ServiceReference> allServices = getMatchingServices();
+ List<ServiceReference> references;
+ if (allServices.isEmpty()) {
+ references = Collections.emptyList();
+ } else {
+ references = m_rankingInterceptor.getServiceReferences(m_dependency, allServices);
+ }
+
+ RankingResult result = computeDifferences(beforeRanking, references);
+ m_selectedReferences = result.selected;
+ return new ChangeSet(getSelectedServices(), result.departures, result.arrivals, oldBest, getFirstService(),
+ null, null);
+ }
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ }
+
+ public boolean isEmpty() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return m_selectedReferences.isEmpty();
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public Comparator<ServiceReference> getComparator() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return m_comparator;
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public void setComparator(Comparator<ServiceReference> cmp) {
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ if (cmp == null) {
+ m_comparator = new ServiceReferenceRankingComparator();
+ } else {
+ m_comparator = cmp;
+ }
+ // Be aware that this method will release the lock to call the dependency callback.
+ setRankingInterceptor(new ComparatorBasedServiceRankingInterceptor(m_comparator));
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ }
+
+ public Filter getFilter() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ return m_filter;
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ public void setRankingInterceptor(ServiceRankingInterceptor interceptor) {
+ m_dependency.getComponentInstance().getFactory().getLogger().log(Log.INFO, "Dependency " + m_dependency.getId
+ () + " is getting a new ranking interceptor : " + interceptor);
+ ChangeSet changeSet;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ ServiceReference oldBest = getFirstService();
+ List<ServiceReference> beforeRanking = getSelectedServices();
+ m_rankingInterceptor = interceptor;
+ m_rankingInterceptor.open(m_dependency);
+
+ final List<ServiceReference> allServices = getMatchingServices();
+ List<ServiceReference> references = Collections.emptyList();
+ if (!allServices.isEmpty()) {
+ references = m_rankingInterceptor.getServiceReferences(m_dependency, allServices);
+ }
+ RankingResult result = computeDifferences(beforeRanking, references);
+ m_selectedReferences = result.selected;
+ changeSet = new ChangeSet(getSelectedServices(), result.departures, result.arrivals, oldBest,
+ getFirstService(), null, null);
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ // Calling onChange outside of the lock.
+ m_dependency.onChange(changeSet);
+ }
+
+ public void close() {
+ reset();
+ }
+
+ public void invalidateMatchingServices() {
+ ChangeSet changeset;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ m_matchingReferences.clear();
+ changeset = computeChangesInMatchingServices();
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+ m_dependency.onChange(changeset);
+ }
+
+ public void invalidateSelectedServices() {
+ ChangeSet changeset;
+ try {
+ m_dependency.acquireWriteLockIfNotHeld();
+ ServiceReference oldBest = getFirstService();
+ List<ServiceReference> beforeRanking = getSelectedServices();
+ m_selectedReferences.clear();
+ final List<ServiceReference> allServices = getMatchingServices();
+ List<ServiceReference> references = Collections.emptyList();
+ if (!allServices.isEmpty()) {
+ references = m_rankingInterceptor.getServiceReferences(m_dependency, allServices);
+ }
+ RankingResult result = computeDifferences(beforeRanking, references);
+ m_selectedReferences = result.selected;
+ changeset = new ChangeSet(getSelectedServices(), result.departures, result.arrivals, oldBest,
+ getFirstService(), null, null);
+ } finally {
+ m_dependency.releaseWriteLockIfHeld();
+ }
+
+ m_dependency.onChange(changeset);
+ }
+
+ /**
+ * Gets the list of tracking interceptors attached to the current service dependency.
+ * @return the list of service references of the tracking interceptors participating to the resolution of the
+ * current service dependency. An empty list is returned is there are no participating interceptors.
+ * @since 1.11.0
+ */
+ public List<ServiceReference> getTrackingInterceptorReferences() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ if (m_trackingInterceptorTracker != null) {
+ List<ServiceReference> refs = m_trackingInterceptorTracker.getUsedServiceReferences();
+ if (refs != null) {
+ return refs;
+ }
+ }
+ return Collections.emptyList();
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets the list of binding interceptors attached to the current service dependency.
+ * @return the list of service references of the binding interceptors participating to the resolution of the
+ * current service dependency. An empty list is returned is there are no participating interceptors.
+ * @since 1.11.0
+ */
+ public List<ServiceReference> getBindingInterceptorReferences() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ if (m_bindingInterceptorTracker != null) {
+ List<ServiceReference> refs = m_bindingInterceptorTracker.getUsedServiceReferences();
+ if (refs != null) {
+ return refs;
+ }
+ }
+ return Collections.emptyList();
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets the service reference of the currently attached ranking interceptor. As only one ranking interceptor can
+ * be attached at a point on time, this is not a list but only one reference.
+ * @return the service reference of the ranking interceptor participating to the resolution of the current
+ * service dependency. {@code null} if no (external) ranking interceptor is currently attached.
+ * @since 1.11.0
+ */
+ public ServiceReference getRankingInterceptorReference() {
+ try {
+ m_dependency.acquireReadLockIfNotHeld();
+ if (m_rankingInterceptorTracker != null) {
+ List<ServiceReference> references = m_rankingInterceptorTracker.getUsedServiceReferences();
+ if (references != null && ! references.isEmpty()) {
+ return references.get(0);
+ }
+ }
+ return null;
+ } finally {
+ m_dependency.releaseReadLockIfHeld();
+ }
+ }
+
+ private class RankingResult {
+ final List<ServiceReference> departures;
+ final List<ServiceReference> arrivals;
+ final List<ServiceReference> selected;
+
+ private RankingResult(List<ServiceReference> departures, List<ServiceReference> arrivals,
+ List<ServiceReference> selected) {
+ this.departures = departures;
+ this.arrivals = arrivals;
+ this.selected = selected;
+ }
+ }
+
+ public class ChangeSet {
+ public final List<ServiceReference> selected;
+ public final List<ServiceReference> departures;
+ public final List<ServiceReference> arrivals;
+ public final ServiceReference oldFirstReference;
+ public final ServiceReference newFirstReference;
+ public final Object service;
+ public final ServiceReference modified;
+
+ public ChangeSet(List<ServiceReference> selectedServices,
+ List<ServiceReference> departures, List<ServiceReference> arrivals,
+ ServiceReference oldFirst, ServiceReference newFirst,
+ Object service, ServiceReference modified) {
+ this.selected = selectedServices;
+ this.departures = departures;
+ this.arrivals = arrivals;
+ this.oldFirstReference = oldFirst;
+ this.newFirstReference = newFirst;
+ this.service = service;
+ this.modified = modified;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceUtils.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceUtils.java
new file mode 100644
index 0000000..b8614e2
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/ServiceReferenceUtils.java
@@ -0,0 +1,145 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.context.ServiceReferenceImpl;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Some utility methods to handle service references.
+ */
+public class ServiceReferenceUtils {
+ /**
+ * Checks if the given service reference match the current filter.
+ * This method aims to avoid calling {@link org.osgi.framework.Filter#match(org.osgi.framework.ServiceReference)}
+ * method when manipulating a composite reference. In fact, this method thrown
+ * a {@link ClassCastException} on Equinox.
+ *
+ * @param ref the service reference to check.
+ * @return <code>true</code> if the service reference matches.
+ */
+ public static boolean match(Filter filter, ServiceReference ref) {
+ boolean match = true;
+ if (filter != null) {
+ if (ref instanceof ServiceReferenceImpl) {
+ // Can't use the match(ref) as it throw a class cast exception on Equinox.
+ //noinspection unchecked
+ match = filter.match(((ServiceReferenceImpl) ref).getProperties());
+ } else { // Non composite reference.
+ match = filter.match(ref);
+ }
+ }
+ return match;
+ }
+
+ /**
+ * Checks whether a list of service references contains a reference with the same {@literal service.id} as the
+ * given reference.
+ * @param references the list of reference
+ * @param ref the reference
+ * @return {@literal true} if references contains a reference with the same service.id as ref.
+ */
+ public static boolean containsReferenceById(List<? extends ServiceReference> references, ServiceReference ref) {
+ return getServiceReferenceById(references, ref) != null;
+ }
+
+ /**
+ * Gets a service reference with the same service.id as the given reference from the given list.
+ * @param references the list of references
+ * @param ref the reference
+ * @return the service reference from references having the same service.id as ref. {@literal null} if there is
+ * no such reference in the list.
+ */
+ public static ServiceReference getServiceReferenceById(List<? extends ServiceReference> references,
+ ServiceReference ref) {
+ Object id = ref.getProperty(Constants.SERVICE_ID);
+ for (ServiceReference reference : references) {
+ if (reference.getProperty(Constants.SERVICE_ID).equals(id)) {
+ return reference;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the two references has the same properties and their value are equals.
+ * @param ref1 first reference
+ * @param ref2 second reference
+ * @return {@literal true} if the two references have the same properties and their values are equals.
+ */
+ public static boolean haveSameProperties(ServiceReference ref1, ServiceReference ref2) {
+ if (ref2 == null && ref1 == null) {
+ return true;
+ }
+
+ if ((ref1 == null) || (ref2 == null)) {
+ return false;
+ }
+
+ String[] keys = ref2.getPropertyKeys();
+
+ if (ref2.getPropertyKeys().length != keys.length) {
+ return false;
+ }
+
+ for (String key : keys) {
+ if (! ref2.getProperty(key).equals(ref1.getProperty(key))) {
+ return false;
+ }
+ }
+
+ return true;
+
+
+ }
+
+ /**
+ * Checks whether two service references have the same service id.
+ * @param ref1 first reference
+ * @param ref2 second reference
+ * @return {@literal true} if the two references have the same service.id, {@literal false} otherwise.
+ */
+ public static boolean haveSameServiceId(ServiceReference ref1, ServiceReference ref2) {
+ return !(ref1 == null || ref2 == null)
+ && ref1.getProperty(Constants.SERVICE_ID).equals(ref2.getProperty(Constants.SERVICE_ID));
+ }
+
+ public static String toString(Collection<? extends ServiceReference> references) {
+ if (references == null || references.isEmpty()) {
+ return "[]";
+ } else {
+ StringBuilder buffer = new StringBuilder("[");
+ for (ServiceReference reference : references) {
+ if (buffer.length() == 1) {
+ buffer.append(reference.getProperty(Constants.SERVICE_ID));
+ } else {
+ buffer.append(", ").append(reference.getProperty(Constants.SERVICE_ID));
+ }
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/TransformedServiceReferenceImpl.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/TransformedServiceReferenceImpl.java
new file mode 100644
index 0000000..c7312fb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/impl/TransformedServiceReferenceImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.ipojo.dependency.interceptors.TransformedServiceReference;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+/**
+ * Implements transformed service reference.
+ */
+public class TransformedServiceReferenceImpl<S> implements TransformedServiceReference<S> {
+
+ private final ServiceReference<S> m_origin;
+ private Map<String, Object> m_properties = new HashMap<String, Object>();
+
+ public TransformedServiceReferenceImpl(ServiceReference<S> origin) {
+ this.m_origin = origin;
+ // Copy properties
+ for (String key : origin.getPropertyKeys()) {
+ m_properties.put(key, origin.getProperty(key));
+ }
+ }
+
+ public TransformedServiceReferenceImpl<S> addProperty(String name, Object value) {
+ if (FORBIDDEN_KEYS.contains(name)) {
+ throw new IllegalArgumentException("Cannot change the property " + name);
+ }
+ m_properties.put(name, value);
+ return this;
+ }
+
+ public TransformedServiceReference<S> addPropertyIfAbsent(String name, Object value) {
+ if (! contains(name)) {
+ addProperty(name, value);
+ }
+ return this;
+ }
+
+ public Object get(String name) {
+ return m_properties.get(name);
+ }
+
+ public TransformedServiceReferenceImpl<S> removeProperty(String name) {
+ if (FORBIDDEN_KEYS.contains(name)) {
+ throw new IllegalArgumentException("Cannot change the property " + name);
+ }
+ // Store a null value.
+ m_properties.put(name, null);
+ return this;
+ }
+
+ public boolean contains(String name) {
+ return m_properties.get(name) != null;
+ }
+
+ public ServiceReference<S> getWrappedReference() {
+ if (m_origin instanceof TransformedServiceReferenceImpl) {
+ return ((TransformedServiceReferenceImpl<S>) m_origin).getWrappedReference();
+ } else {
+ return m_origin;
+ }
+ }
+
+ public Object getProperty(String key) {
+ return m_properties.get(key);
+ }
+
+ public String[] getPropertyKeys() {
+ List<String> keys = new ArrayList<String>();
+ for (Map.Entry<String, Object> entry : m_properties.entrySet()) {
+ if (entry.getValue() != null) {
+ keys.add(entry.getKey());
+ }
+ }
+ return keys.toArray(new String[keys.size()]);
+ }
+
+ public Bundle getBundle() {
+ return m_origin.getBundle();
+ }
+
+ public Bundle[] getUsingBundles() {
+ return m_origin.getUsingBundles();
+ }
+
+ public boolean isAssignableTo(Bundle bundle, String className) {
+ return m_origin.isAssignableTo(bundle, className);
+ }
+
+ /**
+ * Compares two service references.
+ * This method is not delegated as we may have modified some of the properties using for the ranking.
+ * @param reference the reference
+ * @return 0, 1 or -1 depending of the reference.
+ */
+ public int compareTo(Object reference) {
+ ServiceReference other = (ServiceReference) reference;
+
+ Long id = (Long) getProperty(Constants.SERVICE_ID);
+ Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
+
+ if (id.equals(otherId)) {
+ return 0; // same service
+ }
+
+ Object rankObj = getProperty(Constants.SERVICE_RANKING);
+ Object otherRankObj = other.getProperty(Constants.SERVICE_RANKING);
+
+ // If no rank, then spec says it defaults to zero.
+ rankObj = (rankObj == null) ? new Integer(0) : rankObj;
+ otherRankObj = (otherRankObj == null) ? new Integer(0) : otherRankObj;
+
+ // If rank is not Integer, then spec says it defaults to zero.
+ Integer rank = (rankObj instanceof Integer)
+ ? (Integer) rankObj : new Integer(0);
+ Integer otherRank = (otherRankObj instanceof Integer)
+ ? (Integer) otherRankObj : new Integer(0);
+
+ // Sort by rank in ascending order.
+ if (rank.compareTo(otherRank) < 0) {
+ return -1; // lower rank
+ } else if (rank.compareTo(otherRank) > 0) {
+ return 1; // higher rank
+ }
+
+ // If ranks are equal, then sort by service id in descending order.
+ return (id.compareTo(otherId) < 0) ? 1 : -1;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ServiceReference) {
+ Object id1 = ((ServiceReference) o).getProperty(Constants.SERVICE_ID);
+ Object id2 = this.getProperty(Constants.SERVICE_ID);
+ return (id1 != null && id1.equals(id2)) || (id1 == id2);
+ }
+ return m_origin.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return m_origin.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getWrappedReference().toString() + m_properties;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultDependencyInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultDependencyInterceptor.java
new file mode 100644
index 0000000..68bcc7e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultDependencyInterceptor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * A default implementation of the dependency interceptor.
+ * It manages the dependency list guarded by the monitor lock.
+ */
+public class DefaultDependencyInterceptor implements DependencyInterceptor {
+
+ /**
+ * The set of managed dependencies.
+ * Access must be guarded by the monitor lock.
+ */
+ protected final Set<DependencyModel> dependencies = new LinkedHashSet<DependencyModel>();
+
+
+ /**
+ * Closes the interception of the given dependency.
+ * @param dependency the dependency stopping its use of the interceptor
+ */
+ public void close(DependencyModel dependency) {
+ synchronized (this) {
+ dependencies.remove(dependency);
+ }
+ }
+
+ /**
+ * Opens the interception of the given dependency.
+ * @param dependency the dependency starting using the interceptor.
+ */
+ public void open(DependencyModel dependency) {
+ synchronized (this) {
+ dependencies.add(dependency);
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceRankingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceRankingInterceptor.java
new file mode 100644
index 0000000..d3c0c5b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceRankingInterceptor.java
@@ -0,0 +1,71 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Default implementation of the default service ranking interceptor.
+ * This implementation does not sort the given set, so returns it as it is.
+ *
+ * It also provides an `invalidateSelectedServices` method notifying all managed dependencies of a change in the
+ * selection service set.
+ *
+ * onDeparture, onArrival and onModified methods delegates to the getServiceReferences method.
+ */
+public class DefaultServiceRankingInterceptor extends DefaultDependencyInterceptor implements
+ ServiceRankingInterceptor {
+
+ /**
+ * Notifies the managed dependencies of a change in the set of services selected by this interceptor.
+ * The dependency will call the getServiceReferences method to recompute the set of selected services.
+ */
+ public void invalidateSelectedServices() {
+ List<DependencyModel> list = new ArrayList<DependencyModel>();
+ synchronized (this) {
+ list.addAll(dependencies);
+ }
+
+ for (DependencyModel dep : list) {
+ dep.invalidateSelectedServices();
+ }
+ }
+
+
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching) {
+ return matching;
+ }
+
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching, ServiceReference<?> reference) {
+ return getServiceReferences(dependency, matching);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceTrackingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceTrackingInterceptor.java
new file mode 100644
index 0000000..ba02a16
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DefaultServiceTrackingInterceptor.java
@@ -0,0 +1,65 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Default implementation of the default service tracking interceptor.
+ * It accepts all references and keeps the dependencies in the `dependencies` list. This list is guarded by the
+ * monitor lock.
+ *
+ * It also provides an `invalidateMatchingServices` method notifying all managed dependencies of a change in the
+ * matching service set.
+ */
+public class DefaultServiceTrackingInterceptor extends DefaultDependencyInterceptor implements ServiceTrackingInterceptor {
+
+ /**
+ * Default implementation of the accept method.
+ * The default behavior is to accept all services as they are (no transformation).
+ * @param dependency the dependency the dependency
+ * @param context the context of the dependency the bundle context used by the dependency
+ * @param ref the reference the reference to accept, transform or reject
+ * @param <S> the type of service
+ * @return the reference as it is.
+ */
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context, TransformedServiceReference<S> ref) {
+ return ref;
+ }
+
+ /**
+ * Notifies the managed dependencies of a change in the set of services accepted by this interceptor.
+ * The dependency will call the accept method to recompute the set of matching services.
+ */
+ public void invalidateMatchingServices() {
+ List<DependencyModel> list = new ArrayList<DependencyModel>();
+ synchronized (this) {
+ list.addAll(dependencies);
+ }
+
+ for (DependencyModel dep : list) {
+ dep.invalidateMatchingServices();
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DependencyInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DependencyInterceptor.java
new file mode 100644
index 0000000..5c5c696
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/DependencyInterceptor.java
@@ -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.felix.ipojo.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+
+/**
+ * Dependency interceptor are collaborating with the service dependency during the service resolution.
+ *
+ * Interceptors publishes a service property (target) to select the dependencies they handle.
+ *
+ * Notice that interceptor can invalidate the set of service used by a dependency by calling
+ * {@link org.apache.felix.ipojo.util.DependencyModel#invalidateMatchingServices()} and
+ * {@link org.apache.felix.ipojo.util.DependencyModel#invalidateSelectedServices()}.
+ */
+public interface DependencyInterceptor {
+
+ /**
+ * A mandatory property published by provider of this service.
+ * The value must be a LDAP filter (Filter or String). This filter will be confronted to the dependency property.
+ *
+ * @see org.osgi.framework.Filter
+ */
+ public static String TARGET_PROPERTY = "target";
+
+
+ /**
+ * The interceptor is plugged to the given dependency.
+ * @param dependency the dependency starting using the interceptor.
+ */
+ public void open(DependencyModel dependency);
+
+ /**
+ * The interceptor won't be use anymore by the given dependency.
+ * This method is called either when the interceptor is replace or when the instance's dependency is stopping.
+ * @param dependency the dependency stopping its use of the interceptor
+ */
+ public void close(DependencyModel dependency);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java
new file mode 100644
index 0000000..ce749b3
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceBindingInterceptor.java
@@ -0,0 +1,70 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A service to modify / monitor the service bindings.
+ * This service is notified every time the dependency is weaving a new service bindings on un-weaves an existing one.
+ *
+ * Several binding interceptors can be plugged to the same service dependency. In this case,
+ * a chain is created where all interceptor are called in a sequence.
+ *
+ * A binding interceptor cannot modify the existing bindings.
+ *
+ * Obviously an interceptor can be plugged to several dependencies.
+ *
+ * @since 1.11.0
+ */
+public interface ServiceBindingInterceptor extends DependencyInterceptor {
+
+ /**
+ * Notification method when a dependency is weaving a new service binding.
+ * The interceptor can modify the service object. It must <strong>never</strong> return a {@code null} object,
+ * but the receive service object if it does not want to do anything with the service object.
+ *
+ * When the interceptor <em>modifies</em> the service object, the returned object <strong>must</strong> be
+ * compatible with the dependency specification.
+ *
+ * The received service object may already have been <em>wrapped</em> by binding interceptors called before the
+ * current one.
+ *
+ * @param dependency the dependency
+ * @param reference the service reference bound
+ * @param service the service object
+ * @param <S> the service specification
+ * @return the service object to be injected within the component. Must never be {@code null}.
+ */
+ public <S> S getService(DependencyModel dependency, ServiceReference<S> reference, S service);
+
+ /**
+ * Notification method when a dependency is un-weaving a service binding.
+ * The interceptor must released all objects related to this service binding.
+ *
+ * @param dependency the dependency
+ * @param reference the unbound service reference
+ * @param <S> the service specification
+ */
+ public <S> void ungetService(DependencyModel dependency, ServiceReference<S> reference);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java
new file mode 100644
index 0000000..e349c1b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceRankingInterceptor.java
@@ -0,0 +1,81 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.List;
+
+/**
+ * A service to influence the sorting of services on a service dependency.
+ *
+ * Only one ranking interceptor can be plugged on a dependency, but an interceptor can handle several dependencies.
+ *
+ * This interceptors is called to compute the selected set of services from the matching set,
+ * i.e. the set of services that matching the filter (actually accepted by the tracking interceptors).
+ *
+ * @since 1.10.1
+ */
+public interface ServiceRankingInterceptor extends DependencyInterceptor {
+
+ /**
+ * Gets the sorted set of selected reference.
+ * @param dependency the dependency
+ * @param matching the set of service to sort
+ * @return the sorted set of selected reference. This set is a sub-set potentially empty of the given list of
+ * references.
+ */
+ public List<ServiceReference> getServiceReferences(DependencyModel dependency, List<ServiceReference> matching);
+
+ /**
+ * A new service arrives in the matching set. This method is called to retrieve the new sorted set of selected
+ * services.
+ * @param dependency the dependency
+ * @param matching the set of matching service
+ * @param reference the arriving reference
+ * @return the new sorted set of service
+ */
+ public List<ServiceReference> onServiceArrival(DependencyModel dependency, List<ServiceReference> matching,
+ ServiceReference<?> reference);
+
+ /**
+ * A service leaves the matching set. This method is called to retrieve the new sorted set of selected
+ * services.
+ * @param dependency the dependency
+ * @param matching the set of matching service
+ * @param reference the leaving reference
+ * @return the new sorted set of service
+ */
+ public List<ServiceReference> onServiceDeparture(DependencyModel dependency, List<ServiceReference> matching,
+ ServiceReference<?> reference);
+
+ /**
+ * A service from the matching set was modified. This method is called to retrieve the new sorted set of selected
+ * services.
+ * @param dependency the dependency
+ * @param matching the set of matching service
+ * @param reference the modified service
+ * @return the new sorted set of service
+ */
+ public List<ServiceReference> onServiceModified(DependencyModel dependency, List<ServiceReference> matching,
+ ServiceReference<?> reference);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java
new file mode 100644
index 0000000..5a7a316
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/ServiceTrackingInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A service to influence the visibility of services within a service dependency.
+ * This service is called to determine which services from the tracker (base set) is going to the matching set.
+ *
+ * Several tracking interceptors can be plugged to the same service dependency. In this case,
+ * a chain is created where all interceptor can influence the next one. If the dependency has a filter,
+ * a tracking interceptor using this filter is the last interceptor of the chain.
+ *
+ * Obviously an interceptor can be plugged to several dependencies. Conversely, several tracking interceptor can be
+ * plugged to one dependency.
+ *
+ * @since 1.10.1
+ */
+public interface ServiceTrackingInterceptor extends DependencyInterceptor {
+
+ /**
+ * Does the interceptor accepts the reference of not ?
+ * This methods has two goals. It can filter out undesirable services by returning {@literal null}. In addition,
+ * it can <em>transform</em> the service reference to add / remove service properties. In this case,
+ * it must return the <strong>same</strong> instance of {@link TransformedServiceReference},
+ * but with the new set of properties.
+ *
+ * So to filter out the service, return {@literal null}. To accept the service,
+ * return the reference as it is. To transform the service update the service reference and return it.
+ *
+ * When several interceptors are collaborating on the same dependency, a chain is created. The received reference
+ * is the reference modified by the preceding interceptor. Notice that once an interceptor returns {@literal
+ * null} the chain is interrupted and the service rejected.
+ *
+ * @param dependency the dependency
+ * @param context the context of the dependency
+ * @param ref the reference
+ * @param <S> the type of service
+ * @return {@literal null} to filter out the service, the, optionally updated, reference to accept it.
+ */
+ public <S> TransformedServiceReference<S> accept(DependencyModel dependency, BundleContext context,
+ TransformedServiceReference<S> ref);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReference.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReference.java
new file mode 100644
index 0000000..667a3b9
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReference.java
@@ -0,0 +1,88 @@
+/*
+ * 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.dependency.interceptors;
+
+import org.apache.felix.ipojo.Factory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+/**
+ * Transformed service reference is an interface letting updating the properties of a service reference.
+ *
+ * Transformed service reference wraps a <i>real</i> service reference and has all its properties.
+ */
+public interface TransformedServiceReference<S> extends ServiceReference<S> {
+
+ /**
+ * These properties are cannot be removed, added or updated.
+ */
+ public static final List<String> FORBIDDEN_KEYS = Arrays.asList(
+ Constants.SERVICE_ID,
+ Constants.SERVICE_PID,
+ Factory.INSTANCE_NAME_PROPERTY
+ );
+
+
+ /**
+ * Adds a property to the reference
+ * @param name the property name
+ * @param value the value (must not be null)
+ * @return the current transformed service reference
+ */
+ public TransformedServiceReference<S> addProperty(String name, Object value);
+
+ /**
+ * Adds a property to the service reference if this property is not already set on the reference.
+ * @param name the property name
+ * @param value the value
+ * @return the current transformed service reference
+ */
+ public TransformedServiceReference<S> addPropertyIfAbsent(String name, Object value);
+
+ /**
+ * Gets the current value of a property.
+ * @param name the property name
+ * @return the current value of the property, {@literal null} if not in the properties.
+ */
+ public Object get(String name);
+
+ /**
+ * Removes a property from the reference.
+ * @param name the property name
+ * @return the current transformed service reference
+ */
+ public TransformedServiceReference<S> removeProperty(String name);
+
+ /**
+ * Does the service reference contains the given property ?
+ * @param name the property name
+ * @return whether the current reference contains a property with the given name
+ */
+ public boolean contains(String name);
+
+ /**
+ * Gets the wrapped service reference
+ * @return the wrapped service reference
+ */
+ public ServiceReference<S> getWrappedReference();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java
new file mode 100644
index 0000000..7dda5cc
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java
@@ -0,0 +1,61 @@
+/*
+ * 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.extender;
+
+/**
+ * Support class for fluent instance declaration building.
+ * This class can be used to provide values for instance configuration.
+ * Any object can be used as configuration values (List and Maps are accepted for example).
+ *
+ * @since 1.11.2
+ */
+public interface ConfigurationBuilder {
+
+ /**
+ * Provide a property value.
+ * @param name property name
+ * @param value property value
+ * @return this builder
+ */
+ ConfigurationBuilder property(String name, Object value);
+
+ /**
+ * Remove a property from the configuration.
+ * This does not affect already created declarations (from this builder).
+ * @param name property name
+ * @return this builder
+ */
+ ConfigurationBuilder remove(String name);
+
+ /**
+ * Remove all properties from the configuration.
+ * This does not affect already created declarations (from this builder).
+ * @return this builder
+ */
+ ConfigurationBuilder clear();
+
+ /**
+ * Build the declaration handle (contains the instance configuration).
+ * Notice that the declaration is not yet published (no automatic activation).
+ * The client has to do it through {@link DeclarationHandle#publish()}
+ * @return the handle to the configured declaration
+ */
+ DeclarationHandle build();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Declaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Declaration.java
new file mode 100644
index 0000000..e22a1d2
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Declaration.java
@@ -0,0 +1,57 @@
+/*
+ * 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.extender;
+
+/**
+ * A declaration is a creation instruction of an entity (Component type, Factory, Instance...).
+ * All declarations are exposed as services. <em>Processors</em> are tracking the adequate declaration type and create
+ * the entity.
+ * <p/>
+ * Declaration can be <em>bound</em> or <em>unbound</em> whether they are fulfilled. When they are unbound,
+ * a message or/and an error can be set.
+ */
+public interface Declaration {
+ /**
+ * Gets the declaration status.
+ *
+ * @return the current status. As Status are immutable, it returns a new object every time.
+ */
+ Status getStatus();
+
+ /**
+ * Marks the declaration bound.
+ */
+ void bind();
+
+ /**
+ * Unbinds the declaration.
+ *
+ * @param message an explanation
+ */
+ void unbind(String message);
+
+ /**
+ * Unbinds the declaration
+ *
+ * @param message an explanation
+ * @param throwable an error
+ */
+ void unbind(String message, Throwable throwable);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java
new file mode 100644
index 0000000..4cd7fcd
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java
@@ -0,0 +1,127 @@
+/*
+ * 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.extender;
+
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * This service provides a way for users to manage declarations through code.
+ *
+ * Notice that produced declarations are immutable once build. But it is possible to re-use a
+ * builder to share some configuration through instances.
+ *
+ * <pre>
+ * // Obtain the service through the service registry
+ * DeclarationBuilderService service = ...
+ *
+ * // Get a fresh instance builder
+ * DeclarationBuilder builder = service.newInstance("the.full.name.of.the.component.to.instantiate");
+ *
+ * DeclarationHandle handle = builder.name("a-unique-name") // Make sure name is unique for the expected type
+ * .configure()
+ * .property("a-property", "a-value")
+ * .property("another-property", "another-value")
+ * .build();
+ *
+ * // Push the InstanceDeclaration service in the registry
+ * handle.publish();
+ * </pre>
+ *
+ * Except the {@link InstanceBuilder#build()} call, all methods are optional:
+ * <ul>
+ * <li>{@link InstanceBuilder#name(String)}: if no name is provided,
+ * a default one will be generated by iPOJO.</li>
+ * <li>{@link InstanceBuilder#version(String)}: if no version is provided,
+ * the first un-versioned type will be used.</li>
+ * <li>{@link InstanceBuilder#configure()}: if no configuration is required, can be omitted.</li>
+ * <li>{@link InstanceBuilder#type(String)}: can be used to change the <bold>required</bold> component type.</li>
+ * <li>{@link InstanceBuilder#context(org.osgi.framework.BundleContext)}: by default, the bundle context
+ * used to register the created {@link org.apache.felix.ipojo.extender.Declaration} is the one of the
+ * caller. It can be changed though this method.</li>
+ * </ul>
+ *
+ * Once an instance handle has been created, its configuration (name, type, version and properties) is immutable. It can
+ * only be {@linkplain DeclarationHandle#publish() published} (so that the framework will try to instantiate the
+ * instance) or {@linkplain DeclarationHandle#retract() retracted} (framework will remove the instance).
+ *
+ * Notice that all created instances will appear as "coming from" the bundle that requires the
+ * {@link DeclarationBuilderService} service. Just like having a {@literal metadata.xml} file in your
+ * bundle that declares your instances. It is possible to override this default behavior using
+ * {@link InstanceBuilder#context(org.osgi.framework.BundleContext)}.
+ *
+ * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+ * @see org.apache.felix.ipojo.extender.TypeDeclaration
+ * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
+ * @see org.apache.felix.ipojo.extender.InstanceBuilder
+ * @see org.apache.felix.ipojo.extender.ConfigurationBuilder
+ * @see org.apache.felix.ipojo.extender.DeclarationHandle
+ *
+ * @since 1.11.2
+ */
+public interface DeclarationBuilderService {
+
+ /**
+ * Declares a new anonymous instance of a given type.
+ * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String) newInstance(type, null)}</code>.
+ * @param type name of the component to be instantiated (cannot be null).
+ * @return a handle usable to publish / retract the declaration.
+ * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+ */
+ InstanceBuilder newInstance(String type);
+
+ /**
+ * Declares a new instance of a given type.
+ * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String, String) newInstance(type, name, null)}</code>.
+ * @param type name of the component to be instantiated.
+ * @param name name of the new instance (can be null)
+ * @return a handle usable to publish / retract the declaration.
+ * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+ */
+ InstanceBuilder newInstance(String type, String name);
+
+ /**
+ * Declares a new instance of a given type.
+ * @param type name of the component to be instantiated.
+ * @param name name of the new instance (can be null)
+ * @param version version of the expected type (can be null)
+ * @return a handle usable to publish / retract the declaration.
+ * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+ */
+ InstanceBuilder newInstance(String type, String name, String version);
+
+ /**
+ * Declares a new extension (supports new types like {@literal component}, {@literal composite}, {@literal handler}).
+ * @param name name of the type to support (no namespace to be provided)
+ * @param builder associated factory builder
+ * @return a handle usable to publish / retract the declaration.
+ * @see org.apache.felix.ipojo.IPojoFactory
+ * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
+ */
+ DeclarationHandle newExtension(String name, FactoryBuilder builder);
+
+ /**
+ * Declares a new type using the given element description.
+ * @param description description of the component type
+ * @return a handle usable to publish / retract the declaration.
+ * @see org.apache.felix.ipojo.extender.TypeDeclaration
+ */
+ DeclarationHandle newType(Element description);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java
new file mode 100644
index 0000000..499d634
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java
@@ -0,0 +1,50 @@
+/*
+ * 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.extender;
+
+/**
+ * Handle on the associated {@link org.apache.felix.ipojo.extender.Declaration} service.
+ * It can be used to start and/or stop the underlying declaration as well as retrieving its
+ * {@linkplain org.apache.felix.ipojo.extender.Status status} (bound or not).
+ *
+ * @since 1.11.2
+ */
+public interface DeclarationHandle {
+
+ /**
+ * Publish the {@link org.apache.felix.ipojo.extender.Declaration}. If the declaration
+ * is already registered, it's a no-op operation.
+ */
+ void publish();
+
+ /**
+ * Retract the {@link org.apache.felix.ipojo.extender.Declaration} service. If the
+ * declaration is not registered, it's a no-op operation.
+ */
+ void retract();
+
+ /**
+ * Return the current (instant) status of the declaration. Remember that
+ * {@link org.apache.felix.ipojo.extender.Status} is immutable (status does not change over time).
+ * If you want an updated status, call again the {@link #getStatus()} method.
+ * @return the instant status of the {@link org.apache.felix.ipojo.extender.Declaration}
+ */
+ Status getStatus();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ExtensionDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ExtensionDeclaration.java
new file mode 100644
index 0000000..2a1f5c3
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ExtensionDeclaration.java
@@ -0,0 +1,48 @@
+/*
+ * 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.extender;
+
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+
+/**
+ * iPOJO's extension declaration.
+ * This service interface is published to instruct the extender to create a new iPOJO extension (like composite or
+ * handler).
+ */
+public interface ExtensionDeclaration extends Declaration {
+ /**
+ * The service property specifying the extension name.
+ */
+ String EXTENSION_NAME_PROPERTY = "ipojo.extension.name";
+
+ /**
+ * Gets the factory builder to use to create the factories bound to this extension.
+ *
+ * @return the factory builder.
+ */
+ FactoryBuilder getFactoryBuilder();
+
+ /**
+ * Gets the extension name. This name must be unique.
+ *
+ * @return the extension name.
+ */
+ String getExtensionName();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java
new file mode 100644
index 0000000..3e17aa8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * 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.extender;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Support class for fluent instance declaration building.
+ * This class can be used to specify instance details like naming, component's type, component's version.
+ * The {@link #context(org.osgi.framework.BundleContext)} method can be used to override the default
+ * {@link org.osgi.framework.BundleContext} used for declaration service registration.
+ *
+ * @since 1.11.2
+ */
+public interface InstanceBuilder {
+
+ /**
+ * Specify the instance name. Using {@literal null} will result in an anonymous instance.
+ * @param name instance name or {@literal null}
+ * @return this builder
+ */
+ InstanceBuilder name(String name);
+
+ /**
+ * Specify the component's type of this instance.
+ * @param type type of the instance (cannot be {@literal null}).
+ * @return this builder
+ */
+ InstanceBuilder type(String type);
+
+ /**
+ * Specify the component's type of this instance.
+ * @param type type of the instance (cannot be {@literal null}).
+ * @return this builder
+ */
+ InstanceBuilder type(Class<?> type);
+
+ /**
+ * Specify the component's version of this instance. If {@literal null} is used,
+ * the factory without any version attribute will be used.
+ * @param version component's version (can be {@literal null}).
+ * @return this builder
+ */
+ InstanceBuilder version(String version);
+
+ /**
+ * Override the default BundleContext used for declaration service registration.
+ * Use this with <bold>caution</bold>, for example, if the bundle does not import the
+ * <code>{@link org.apache.felix.ipojo.extender}</code> package, declarations may not be
+ * linked and activated properly.
+ * @param context new context to be used.
+ * @return this builder
+ */
+ InstanceBuilder context(BundleContext context);
+
+ /**
+ * Access the dedicated builder for configuration (properties).
+ * Notice that when this method is used, the called must use {@link ConfigurationBuilder#build()}
+ * to build the instance declaration configured with the right set of properties. Any attempt
+ * to use {@link #build()} will result in a new declaration with no properties associated.
+ *
+ * Good usage (produced declaration has the associated properties):
+ * <pre>
+ * DeclarationHandle handle = builder.configure()
+ * .property("hello", "world")
+ * .build();
+ * </pre>
+ *
+ * Bad usage (produced declaration does not have the associated properties):
+ * <pre>
+ * builder.configure()
+ * .property("hello", "world");
+ *
+ * DeclarationHandle handle = builder.build();
+ * </pre>
+ *
+ * @return the instance configuration builder
+ */
+ ConfigurationBuilder configure();
+
+ /**
+ * Build the declaration handle (never contains any configuration).
+ * Notice that the declaration is not yet published (no automatic activation).
+ * The client has to do it through {@link DeclarationHandle#publish()}
+ * @return the handle to the declaration
+ */
+ DeclarationHandle build();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceDeclaration.java
new file mode 100644
index 0000000..66f025e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceDeclaration.java
@@ -0,0 +1,80 @@
+/*
+ * 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.extender;
+
+import org.osgi.framework.Bundle;
+
+import java.util.Dictionary;
+
+/**
+ * Service published to instruct an instance creation.
+ */
+public interface InstanceDeclaration extends Declaration {
+ /**
+ * Service property specifying the component type's name.
+ */
+ String COMPONENT_NAME_PROPERTY = "ipojo.component.name";
+
+ /**
+ * Service property specifying the component type's version.
+ */
+ String COMPONENT_VERSION_PROPERTY = "ipojo.component.version";
+
+ /**
+ * Service property specifying the instance name.
+ */
+ String INSTANCE_NAME = "ipojo.instance.name";
+
+ /**
+ * Value used when an instance configuration does not declare its name.
+ */
+ String UNNAMED_INSTANCE = "unnamed";
+
+ /**
+ * The instance configuration.
+ *
+ * @return the instance configuration
+ */
+ Dictionary<String, Object> getConfiguration();
+
+ /**
+ * @return the component type's name.
+ */
+ String getComponentName();
+
+ /**
+ * @return the component type's version, {@literal null} if not set.
+ */
+ String getComponentVersion();
+
+ /**
+ * Gets the instance name.
+ *
+ * @return the instance name, {@literal unnamed} if not specified.
+ */
+ String getInstanceName();
+
+ /**
+ * Gets the bundle that is declaring this instance.
+ * @return the bundle object
+ * @since 1.11.2
+ */
+ Bundle getBundle();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Status.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Status.java
new file mode 100644
index 0000000..c9a98db
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/Status.java
@@ -0,0 +1,49 @@
+/*
+ * 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.extender;
+
+/**
+ * The declaration status.
+ * A declaration may be fulfilled or not (bound or not).
+ * When the declaration is unbound, a message can be given to explain the reason.
+ * Implementation are immutable.
+ */
+public interface Status {
+ /**
+ * Is the declaration fulfilled ?
+ *
+ * @return {@literal true} if the declaration is bound, {@literal false} otherwise.
+ */
+ boolean isBound();
+
+ /**
+ * Gets the unbound message if any.
+ *
+ * @return the unbound message, <code>null</code> if no message.
+ */
+ String getMessage();
+
+ /**
+ * Gets the unbound error if any.
+ *
+ * @return the unbound error, <code>null</code> if no error were set.
+ */
+ Throwable getThrowable();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/TypeDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/TypeDeclaration.java
new file mode 100644
index 0000000..167aa2a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/TypeDeclaration.java
@@ -0,0 +1,63 @@
+/*
+ * 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.extender;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Service exposed to instruct a factory creation.
+ */
+public interface TypeDeclaration extends Declaration {
+
+ /**
+ * Get the component metadata description.
+ *
+ * @return the component metadata description.
+ */
+ Element getComponentMetadata();
+
+ /**
+ * Returns {@literal true} if the type is public
+ *
+ * @return {@literal true} if the type is public
+ */
+ boolean isPublic();
+
+ /**
+ * Gets the component type's name.
+ *
+ * @return the component type's name.
+ */
+ String getComponentName();
+
+ /**
+ * Gets the component type's version.
+ *
+ * @return the component type's version
+ */
+ String getComponentVersion();
+
+ /**
+ * Gets the targeted iPOJO Extension (primitive, composite, handler...)
+ *
+ * @return the targeted extension
+ */
+ String getExtension();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilder.java
new file mode 100644
index 0000000..167187b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * 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.extender.builder;
+
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Interface defining the method used to build {@link IPojoFactory} instances.
+ * As each type of iPOJO factories can be different, factory builder are the common facade of all those types.
+ */
+public interface FactoryBuilder {
+
+ /**
+ * Creates an iPOJO Factory.
+ *
+ * @param bundleContext the bundle context of the bundle declaring the component type
+ * @param metadata the metadata of the component type (<code>component</code> element).
+ * @return the iPOJO Factory instance.
+ * @throws FactoryBuilderException if the factory cannot be created.
+ */
+ IPojoFactory build(BundleContext bundleContext, Element metadata) throws FactoryBuilderException;
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilderException.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilderException.java
new file mode 100644
index 0000000..bec872b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/builder/FactoryBuilderException.java
@@ -0,0 +1,46 @@
+/*
+ * 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.extender.builder;
+
+/**
+ * Exception thrown by {@link FactoryBuilder} when a {@link org.apache.felix.ipojo.IPojoFactory} instance cannot be
+ * created correctly.
+ */
+public class FactoryBuilderException extends Exception {
+
+ /**
+ * Creates the exception instance with the given message.
+ *
+ * @param message the message
+ */
+ public FactoryBuilderException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates the exception instance with the given message and cause.
+ *
+ * @param message the message
+ * @param cause the cause
+ */
+ public FactoryBuilderException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java
new file mode 100644
index 0000000..9f0a9b2
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java
@@ -0,0 +1,104 @@
+/*
+ * 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.extender.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+
+/**
+ * Common code wrapping an OSGi service.
+ */
+public abstract class AbstractService implements Lifecycle {
+
+ /**
+ * The bundle context.
+ * To let sub-classes retrieve the used bundle context, this member is {@literal protected}.
+ */
+ protected final BundleContext m_bundleContext;
+ /**
+ * The service specification.
+ */
+ private final Class<?> m_type;
+ /**
+ * The service registration.
+ */
+ private ServiceRegistration<?> m_registration;
+
+
+ /**
+ * Constructor.
+ * This constructor checks that the current class and the service specification are compatible.
+ *
+ * @param bundleContext the bundle context
+ * @param type the specification
+ */
+ protected AbstractService(BundleContext bundleContext, Class<?> type) {
+ m_bundleContext = bundleContext;
+ if (!type.isAssignableFrom(getClass())) {
+ throw new IllegalArgumentException("This object is not an instance of " + type.getName());
+ }
+ m_type = type;
+ }
+
+ /**
+ * On start, registers the service.
+ */
+ public void start() {
+ m_registration = registerService();
+ }
+
+ protected ServiceRegistration<?> registerService() {
+ return m_bundleContext.registerService(m_type.getName(), this, getServiceProperties());
+ }
+
+ /**
+ * On stop, un-registers the service.
+ */
+ public void stop() {
+ if (m_registration != null) {
+ m_registration.unregister();
+ m_registration = null;
+ }
+ }
+
+ /**
+ * @return the service properties, {@literal null} by default.
+ */
+ protected Dictionary<String, ?> getServiceProperties() {
+ return null;
+ }
+
+ protected BundleContext getBundleContext() {
+ return m_bundleContext;
+ }
+
+ protected ServiceRegistration<?> getRegistration() {
+ return m_registration;
+ }
+
+ /**
+ * Is this service registered or not ?
+ */
+ public boolean isRegistered() {
+ return m_registration != null;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/BundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/BundleProcessor.java
new file mode 100644
index 0000000..740b401
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/BundleProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.extender.internal;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Main Processor interface.
+ * A bundle processor is an extender fragment, it analyzes the bundle content and creates the entities.
+ * <p/>
+ * Notice the difference between the <code>activate / deactivate </code> methods called when a bundle is starting
+ * and stopping, and <code>start / stop</code> called when the iPOJO bundle is started and stopped.
+ */
+public interface BundleProcessor extends Lifecycle {
+ /**
+ * A bundle is started.
+ *
+ * @param bundle the bundle
+ */
+ void activate(Bundle bundle);
+
+ /**
+ * A bundle is stopping. This call is made during the stopping phase.
+ *
+ * @param bundle the bundle
+ */
+ void deactivate(Bundle bundle);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/DefaultJob.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/DefaultJob.java
new file mode 100644
index 0000000..cc84f29
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/DefaultJob.java
@@ -0,0 +1,67 @@
+/*
+ * 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.extender.internal;
+
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleReference;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A callable object implementing Bundle Reference.
+ * It makes the Bundle object accessible by the processing job.
+ * This class is intended to be extended.
+ */
+public abstract class DefaultJob<T> implements Job<T> {
+ /**
+ * The bundle object.
+ */
+ private final Bundle m_bundle;
+
+ /**
+ * Jobb type identifier;
+ */
+ private final String m_jobType;
+
+ /**
+ * Creates the ReferenceableCallable instance.
+ *
+ * @param bundle the associated bundle
+ * @param jobType job type identifier
+ */
+ protected DefaultJob(Bundle bundle, String jobType) {
+ m_bundle = bundle;
+ m_jobType = jobType;
+ }
+
+ /**
+ * Gets the bundle object.
+ *
+ * @return the bundle
+ */
+ public Bundle getBundle() {
+ return m_bundle;
+ }
+
+ public String getJobType() {
+ return m_jobType;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java
new file mode 100644
index 0000000..492a31d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java
@@ -0,0 +1,340 @@
+/*
+ * 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.extender.internal;
+
+import java.util.concurrent.ThreadFactory;
+
+import org.apache.felix.ipojo.ConfigurationTracker;
+import org.apache.felix.ipojo.EventDispatcher;
+import org.apache.felix.ipojo.extender.internal.declaration.service.DeclarationServiceFactory;
+import org.apache.felix.ipojo.extender.internal.linker.DeclarationLinker;
+import org.apache.felix.ipojo.extender.internal.processor.*;
+import org.apache.felix.ipojo.extender.internal.queue.ExecutorQueueService;
+import org.apache.felix.ipojo.extender.internal.queue.GroupThreadFactory;
+import org.apache.felix.ipojo.extender.internal.queue.NamingThreadFactory;
+import org.apache.felix.ipojo.extender.internal.queue.PrefixedThreadFactory;
+import org.apache.felix.ipojo.extender.internal.queue.SynchronousQueueService;
+import org.apache.felix.ipojo.extender.internal.queue.debug.ReplayQueueEventProxy;
+import org.apache.felix.ipojo.extender.internal.queue.pref.HeaderPreferenceSelection;
+import org.apache.felix.ipojo.extender.internal.queue.pref.Preference;
+import org.apache.felix.ipojo.extender.internal.queue.pref.PreferenceQueueService;
+import org.apache.felix.ipojo.extender.internal.queue.pref.enforce.EnforcedQueueService;
+import org.apache.felix.ipojo.extender.queue.debug.QueueEventProxy;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.*;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+
+/**
+ * iPOJO main activator.
+ */
+public class Extender implements BundleActivator {
+ public static final String BOOTSTRAP_QUEUE_DEBUG_PROPERTY = "org.apache.felix.ipojo.extender.BootstrapQueueDebug";
+ /**
+ * Enables the iPOJO internal dispatcher.
+ * This internal dispatcher helps the OSGi framework to support large
+ * scale applications. The internal dispatcher is disabled by default.
+ */
+ static boolean DISPATCHER_ENABLED = true;
+
+ /**
+ * Disables the iPOJO asynchronous processing.
+ * When set to false, the bundles are processed in the listener thread
+ * making iPOJO usable on Google App Engine. By default, the processing
+ * is asynchronous.
+ */
+ static boolean SYNCHRONOUS_PROCESSING_ENABLED = false;
+
+ /**
+ * Property allowing to set if the internal dispatcher is enabled or disabled.
+ * Possible value are either {@literal true} or {@literal false}.
+ */
+ private static final String ENABLING_DISPATCHER = "ipojo.internal.dispatcher";
+
+ /**
+ * Property allowing to disable the asynchronous process (and so enables the
+ * synchronous processing).
+ * Possible value are either {@literal true} or {@literal false}.
+ */
+ private static final String SYNCHRONOUS_PROCESSING = "ipojo.processing.synchronous";
+
+ /**
+ * The Bundle Context of the iPOJO Core bundle.
+ */
+ private static BundleContext m_context;
+
+ /**
+ * The iPOJO Extender logger.
+ */
+ private Logger m_logger;
+
+ /**
+ * The iPOJO Bundle.
+ */
+ private Bundle m_bundle;
+
+ /**
+ * The chained processor containing all the true bundle processor.
+ */
+ private ChainedBundleProcessor m_processor;
+
+ /**
+ * Binds Instances to Factories to Extensions.
+ */
+ private DeclarationLinker m_linker;
+
+ private LifecycleQueueService m_queueService;
+
+ /**
+ * Track ACTIVE bundles.
+ */
+ private BundleTracker m_tracker;
+
+ /**
+ * Service provided to build declarations through code.
+ */
+ private DeclarationServiceFactory m_declarationService;
+
+ /**
+ * The iPOJO bundle is starting.
+ * This method configures the iPOJO system (internal dispatcher and bundle processing). Then it initiates the
+ * bundle processing.
+ * <p/>
+ * To optimize the processing, we process the iPOJO bundle first.
+ *
+ * @param context the iPOJO's bundle bundle context
+ * @throws Exception something terrible happen during startup
+ */
+ public void start(BundleContext context) throws Exception {
+ m_context = context;
+ m_bundle = context.getBundle();
+
+ m_logger = new Logger(m_context, "IPOJO-Main-Extender");
+
+ enablingDispatcher(context, m_logger);
+ enablingSynchronousProcessing(context, m_logger);
+
+ // Create the dispatcher only if required.
+ if (DISPATCHER_ENABLED) {
+ EventDispatcher.create(context);
+ }
+
+ // Initialize ConfigurationTracker
+ ConfigurationTracker.initialize();
+
+ // Initialize the queue event proxy if wanted
+ ReplayQueueEventProxy proxy = null;
+ if (Boolean.getBoolean(BOOTSTRAP_QUEUE_DEBUG_PROPERTY)) {
+ proxy = new ReplayQueueEventProxy();
+ context.registerService(QueueEventProxy.class, proxy, null);
+ }
+
+ BundleProcessor extensionBundleProcessor = new ExtensionBundleProcessor(m_logger);
+ BundleProcessor componentsProcessor = new ComponentsBundleProcessor(m_logger);
+ BundleProcessor configurationProcessor = new ConfigurationProcessor(m_logger);
+ if (SYNCHRONOUS_PROCESSING_ENABLED) {
+ m_queueService = new EnforcedQueueService(
+ new HeaderPreferenceSelection(),
+ new SynchronousQueueService(context),
+ Preference.SYNC,
+ m_logger);
+
+ // If required, add the event proxy
+ if (proxy != null) {
+ m_queueService.addQueueListener(proxy);
+ }
+ } else {
+ // Build a thread factory that will groups extender's thread together
+ ThreadFactory threadFactory = new GroupThreadFactory(new ThreadGroup("iPOJO Extender"));
+ threadFactory = new NamingThreadFactory(threadFactory);
+ threadFactory = new PrefixedThreadFactory(threadFactory, "[iPOJO] ");
+
+ // Create the queue services
+ SynchronousQueueService sync = new SynchronousQueueService(context);
+ ExecutorQueueService async = new ExecutorQueueService(context,
+ Integer.getInteger(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY,
+ 1), // default to 1 if no system property is set
+ threadFactory);
+ m_queueService = new PreferenceQueueService(new HeaderPreferenceSelection(), sync, async);
+
+ extensionBundleProcessor = new QueuingActivationProcessor(extensionBundleProcessor, m_queueService);
+ componentsProcessor = new QueuingActivationProcessor(componentsProcessor, m_queueService);
+ configurationProcessor = new QueuingActivationProcessor(configurationProcessor, m_queueService);
+
+ // If required, add the event proxy to both real services
+ if (proxy != null) {
+ sync.addQueueListener(proxy);
+ async.addQueueListener(proxy);
+ }
+
+ }
+ m_queueService.start();
+
+ // Start linking
+ m_linker = new DeclarationLinker(context, m_queueService);
+ m_linker.start();
+
+ m_processor = ChainedBundleProcessor.create(extensionBundleProcessor, componentsProcessor, configurationProcessor);
+
+ m_processor.start();
+
+ // Begin by initializing core handlers
+ m_processor.activate(m_bundle);
+
+ m_tracker = new BundleTracker(context, Bundle.ACTIVE, new BundleTrackerCustomizer() {
+ public Object addingBundle(final Bundle bundle, final BundleEvent event) {
+ if (bundle.getBundleId() == m_bundle.getBundleId()) {
+ // Not interested in our own bundle
+ return null;
+ }
+ m_processor.activate(bundle);
+ return bundle;
+ }
+
+ public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Object object) {}
+
+ public void removedBundle(final Bundle bundle, final BundleEvent event, final Object object) {
+ m_processor.deactivate(bundle);
+ }
+ });
+
+ m_tracker.open();
+
+ m_declarationService = new DeclarationServiceFactory(context);
+ m_declarationService.start();
+
+ m_logger.log(Logger.INFO, "iPOJO Main Extender started");
+ }
+
+ /**
+ * The iPOJO bundle is stopping.
+ *
+ * @param context the bundle context
+ * @throws Exception something terrible happen
+ */
+ public void stop(BundleContext context) throws Exception {
+
+ m_declarationService.stop();
+
+ m_tracker.close();
+
+ m_processor.deactivate(m_bundle);
+
+ //Shutdown ConfigurationTracker
+ ConfigurationTracker.shutdown();
+
+ m_processor.stop();
+
+ if (DISPATCHER_ENABLED) {
+ EventDispatcher.dispose();
+ }
+
+ m_linker.stop();
+ m_queueService.stop();
+
+ m_logger.log(Logger.INFO, "iPOJO Main Extender stopped");
+ m_context = null;
+ }
+
+ /**
+ * Gets iPOJO bundle context.
+ *
+ * @return the iPOJO Bundle Context
+ */
+ public static BundleContext getIPOJOBundleContext() {
+ return m_context;
+ }
+
+ /**
+ * Enables or disables the internal dispatcher, so sets the
+ * {@link Extender#DISPATCHER_ENABLED} flag.
+ * This method checks if the {@link Extender#ENABLING_DISPATCHER}
+ * property is set to {@literal true}. Otherwise, the internal
+ * dispatcher is disabled. The property can be set as a system
+ * property ({@literal ipojo.internal.dispatcher}) or inside the
+ * iPOJO bundle manifest ({@literal ipojo-internal-dispatcher}).
+ *
+ * @param context the bundle context.
+ * @param logger the logger to indicates if the internal dispatcher is set.
+ */
+ private static void enablingDispatcher(BundleContext context, Logger logger) {
+ // First check in the framework and in the system properties
+ String flag = context.getProperty(ENABLING_DISPATCHER);
+
+ // If null, look in bundle manifest
+ if (flag == null) {
+ String key = ENABLING_DISPATCHER.replace('.', '-');
+ flag = (String) context.getBundle().getHeaders().get(key);
+ }
+
+ if (flag != null) {
+ if (flag.equalsIgnoreCase("true")) {
+ Extender.DISPATCHER_ENABLED = true;
+ logger.log(Logger.INFO, "iPOJO Internal Event Dispatcher enables");
+ return;
+ }
+ }
+
+ // Either l is null, or the specified value was false
+ Extender.DISPATCHER_ENABLED = false;
+ logger.log(Logger.INFO, "iPOJO Internal Event Dispatcher disables");
+
+ }
+
+ /**
+ * Enables or disables the asynchronous processing, so sets the
+ * {@link Extender#SYNCHRONOUS_PROCESSING_ENABLED} flag.
+ * Disabling asynchronous processing avoids iPOJO to create a new
+ * thread to process bundles. So, iPOJO can be used on the
+ * Google App Engine.
+ * This method checks if the {@link Extender#SYNCHRONOUS_PROCESSING}
+ * property is set to {@literal true}. Otherwise, asynchronous processing
+ * is used (default). The property can be set as a system
+ * property ({@literal ipojo.processing.synchronous}) or inside the
+ * iPOJO bundle manifest.
+ *
+ * @param context the bundle context.
+ * @param logger the logger to indicates if the internal dispatcher is set.
+ */
+ private static void enablingSynchronousProcessing(BundleContext context, Logger logger) {
+ String flag = context.getProperty(SYNCHRONOUS_PROCESSING);
+
+ // If null, look in bundle manifest
+ if (flag == null) {
+ String key = SYNCHRONOUS_PROCESSING.replace('.', '-');
+ flag = (String) context.getBundle().getHeaders().get(key);
+ }
+
+ if (flag != null) {
+ if (flag.equalsIgnoreCase("true")) {
+ Extender.SYNCHRONOUS_PROCESSING_ENABLED = true;
+ logger.log(Logger.INFO, "iPOJO Asynchronous processing disabled");
+ return;
+ }
+ }
+
+ // Either l is null, or the specified value was false
+ Extender.SYNCHRONOUS_PROCESSING_ENABLED = false;
+ logger.log(Logger.INFO, "iPOJO synchronous processing disabled");
+
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Lifecycle.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Lifecycle.java
new file mode 100644
index 0000000..2706ca1
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Lifecycle.java
@@ -0,0 +1,36 @@
+/*
+ * 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.extender.internal;
+
+/**
+ * Simple start/stop interface.
+ */
+public interface Lifecycle {
+
+ /**
+ * Start the service.
+ */
+ void start();
+
+ /**
+ * Stop the service.
+ */
+ void stop();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/LifecycleQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/LifecycleQueueService.java
new file mode 100644
index 0000000..97024f3
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/LifecycleQueueService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.extender.internal;
+
+import org.apache.felix.ipojo.extender.queue.QueueService;
+
+/**
+ * An interface composing {@link QueueService} and {@link Lifecycle}.
+ */
+public interface LifecycleQueueService extends QueueService, Lifecycle {
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/builder/ReflectiveFactoryBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/builder/ReflectiveFactoryBuilder.java
new file mode 100644
index 0000000..c7b0f55
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/builder/ReflectiveFactoryBuilder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.extender.internal.builder;
+
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilderException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An Factory builder using a reflective call to build the factory.
+ * <p/>
+ * This builder is compatible with the original iPOJO method consisting in calling a constructor receiving the bundle
+ * context and the metadata as parameters.
+ * <p/>
+ * This factory builder need the constructor to be called.
+ */
+public class ReflectiveFactoryBuilder implements FactoryBuilder {
+
+ /**
+ * The constructor to call.
+ */
+ private final Constructor<? extends IPojoFactory> m_constructor;
+
+ /**
+ * Creates the factory builder.
+ *
+ * @param constructor the constructor that will be called when a new component factory will be created.
+ */
+ public ReflectiveFactoryBuilder(Constructor<? extends IPojoFactory> constructor) {
+ m_constructor = constructor;
+ }
+
+ /**
+ * Calls the wrapped constructor to create an iPOJO factory.
+ *
+ * @param bundleContext the bundle context of the bundle declaring the component type
+ * @param metadata the metadata of the component type (<code>component</code> element).
+ * @return the created iPOJO factory
+ * @throws FactoryBuilderException if the constructor cannot be called or throws an error.
+ */
+ public IPojoFactory build(BundleContext bundleContext, Element metadata) throws FactoryBuilderException {
+ try {
+ return m_constructor.newInstance(bundleContext, metadata);
+ } catch (InstantiationException e) {
+ throw new FactoryBuilderException("Cannot create instance of " + m_constructor.getDeclaringClass(), e);
+ } catch (IllegalAccessException e) {
+ throw new FactoryBuilderException(m_constructor.getDeclaringClass() + " constructor is not " +
+ "accessible (not public)", e);
+ } catch (InvocationTargetException e) {
+ throw new FactoryBuilderException("Cannot create instance of " + m_constructor.getDeclaringClass(), e);
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java
new file mode 100644
index 0000000..69197e8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java
@@ -0,0 +1,148 @@
+/*
+ * 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.extender.internal.declaration;
+
+import org.apache.felix.ipojo.extender.Declaration;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.Status;
+import org.apache.felix.ipojo.extender.internal.AbstractService;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Common code to all Declaration objects.
+ */
+public abstract class AbstractDeclaration extends AbstractService implements Declaration, DeclarationHandle, Status {
+
+ /**
+ * The message used when a declaration is bound.
+ */
+
+ public static final String DECLARATION_BOUND_MESSAGE = "Declaration bound";
+ /**
+ * Is the declaration bound (i.e. successfully fulfilled), or not.
+ */
+ private boolean m_bound = false;
+
+ /**
+ * When not bound, the reason, otherwise {@link #DECLARATION_BOUND_MESSAGE}
+ */
+ private String m_message;
+
+ /**
+ * If an error was thrown during the binding, the error.
+ */
+ private Throwable m_throwable;
+
+ protected AbstractDeclaration(BundleContext bundleContext, Class<?> type) {
+ super(bundleContext, type);
+ }
+
+ /**
+ * @return whether the declaration is bound or not.
+ */
+ public boolean isBound() {
+ return m_bound;
+ }
+
+ /**
+ * @return the message. The message contains the not-bound reason.
+ */
+ public String getMessage() {
+ return m_message;
+ }
+
+ /**
+ * @return the error if something went wrong during the binding process.
+ */
+ public Throwable getThrowable() {
+ return m_throwable;
+ }
+
+ /**
+ * Gets the status of the declaration. This method returns an immutable object.
+ *
+ * @return the declaration status.
+ */
+ public Status getStatus() {
+ // We return an immutable object, created on the fly.
+ return new Status() {
+ final boolean m_bound = AbstractDeclaration.this.m_bound;
+ final String m_message = AbstractDeclaration.this.m_message;
+ final Throwable m_throwable = AbstractDeclaration.this.m_throwable;
+
+ public boolean isBound() {
+ return this.m_bound;
+ }
+
+ public String getMessage() {
+ return this.m_message;
+ }
+
+ public Throwable getThrowable() {
+ return this.m_throwable;
+ }
+ };
+ }
+
+ /**
+ * Binds the declaration.
+ * This method just set the status, message and error.
+ */
+ public void bind() {
+ m_bound = true;
+ m_message = DECLARATION_BOUND_MESSAGE;
+ m_throwable = null;
+ }
+
+ /**
+ * Unbinds the declaration.
+ *
+ * @param message an explanation
+ * @see #unbind(String, Throwable)
+ */
+ public void unbind(String message) {
+ unbind(message, null);
+ }
+
+ /**
+ * Unbinds the declaration.
+ * The flag, message and error are set.
+ *
+ * @param message an explanation
+ * @param throwable an error
+ */
+ public void unbind(String message, Throwable throwable) {
+ m_bound = false;
+ m_message = message;
+ m_throwable = throwable;
+ }
+
+ public void publish() {
+ if (!isRegistered()) {
+ start();
+ }
+ }
+
+ public void retract() {
+ if (isRegistered()) {
+ stop();
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclaration.java
new file mode 100644
index 0000000..2d91ef7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclaration.java
@@ -0,0 +1,64 @@
+/*
+ * 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.extender.internal.declaration;
+
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.osgi.framework.BundleContext;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+/**
+ * Default implementation of the iPOJO Extension Declaration.
+ */
+public class DefaultExtensionDeclaration extends AbstractDeclaration implements ExtensionDeclaration {
+
+ private final FactoryBuilder m_factoryBuilder;
+ private final String m_type;
+
+ public DefaultExtensionDeclaration(BundleContext bundleContext, FactoryBuilder factoryBuilder, String type) {
+ super(bundleContext, ExtensionDeclaration.class);
+ m_factoryBuilder = factoryBuilder;
+ m_type = type;
+ }
+
+ public FactoryBuilder getFactoryBuilder() {
+ return m_factoryBuilder;
+ }
+
+ public String getExtensionName() {
+ return m_type;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ bind();
+ }
+
+ @Override
+ protected Dictionary<String, ?> getServiceProperties() {
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+ properties.put(ExtensionDeclaration.EXTENSION_NAME_PROPERTY, m_type);
+ return properties;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclaration.java
new file mode 100644
index 0000000..6f8bfc7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclaration.java
@@ -0,0 +1,107 @@
+/*
+ * 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.extender.internal.declaration;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+/**
+ * Default implementation of the instance declaration.
+ */
+public class DefaultInstanceDeclaration extends AbstractDeclaration implements InstanceDeclaration {
+
+ private static final Dictionary<String, Object> EMPTY_DICTIONARY = new Hashtable<String, Object>();
+
+ private final String m_componentName;
+ private final Dictionary<String, Object> m_configuration;
+ private final String m_componentVersion;
+ private final String m_instanceName;
+
+ public DefaultInstanceDeclaration(BundleContext bundleContext, String componentName) {
+ this(bundleContext, componentName, EMPTY_DICTIONARY);
+ }
+
+ public DefaultInstanceDeclaration(BundleContext bundleContext, String componentName, Dictionary<String, Object> configuration) {
+ super(bundleContext, InstanceDeclaration.class);
+ m_componentName = componentName;
+ m_configuration = configuration;
+ m_componentVersion = initComponentVersion();
+ m_instanceName = initInstanceName();
+ }
+
+ private String initInstanceName() {
+ String name = (String) m_configuration.get(Factory.INSTANCE_NAME_PROPERTY);
+ if (name == null) {
+ name = UNNAMED_INSTANCE;
+ }
+ return name;
+ }
+
+ private String initComponentVersion() {
+ return (String) m_configuration.get(Factory.FACTORY_VERSION_PROPERTY);
+ }
+
+ public Dictionary<String, Object> getConfiguration() {
+ return m_configuration;
+ }
+
+ public String getComponentName() {
+ return m_componentName;
+ }
+
+ public String getComponentVersion() {
+ return m_componentVersion;
+ }
+
+ public String getInstanceName() {
+ return m_instanceName;
+ }
+
+ /**
+ * Gets the bundle that is declaring this instance.
+ *
+ * @return the bundle object
+ * @since 1.11.2
+ */
+ public Bundle getBundle() {
+ return m_bundleContext.getBundle();
+ }
+
+ @Override
+ protected Dictionary<String, ?> getServiceProperties() {
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+ properties.put(InstanceDeclaration.COMPONENT_NAME_PROPERTY, m_componentName);
+
+ String version = getComponentVersion();
+ if (version != null) {
+ properties.put(InstanceDeclaration.COMPONENT_VERSION_PROPERTY, version);
+ }
+
+ properties.put(InstanceDeclaration.INSTANCE_NAME, m_instanceName);
+
+ return properties;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclaration.java
new file mode 100644
index 0000000..42b1958
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclaration.java
@@ -0,0 +1,96 @@
+/*
+ * 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.extender.internal.declaration;
+
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+/**
+ * Default implementation of the component type declaration.
+ */
+public class DefaultTypeDeclaration extends AbstractDeclaration implements TypeDeclaration {
+
+ private final Element m_componentMetadata;
+ private final String m_componentName;
+ private final String m_componentVersion;
+ private final String m_extension;
+ private boolean visible = true;
+
+ public DefaultTypeDeclaration(BundleContext bundleContext, Element componentMetadata) {
+ super(bundleContext, TypeDeclaration.class);
+ m_componentMetadata = componentMetadata;
+ visible = initVisible();
+ m_componentName = initComponentName();
+ m_componentVersion = initComponentVersion(bundleContext);
+ m_extension = initExtension();
+ }
+
+ private String initExtension() {
+ if (m_componentMetadata.getNameSpace() == null) {
+ return m_componentMetadata.getName();
+ }
+ return m_componentMetadata.getNameSpace() + ":" + m_componentMetadata.getName();
+ }
+
+ private String initComponentVersion(BundleContext bundleContext) {
+ String version = m_componentMetadata.getAttribute("version");
+ if (version != null) {
+ if ("bundle".equalsIgnoreCase(version)) {
+ return bundleContext.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
+ }
+ }
+ return version;
+ }
+
+ private String initComponentName() {
+ String name = m_componentMetadata.getAttribute("name");
+ if (name == null) {
+ name = m_componentMetadata.getAttribute("classname");
+ }
+ return name;
+ }
+
+ private boolean initVisible() {
+ String publicAttribute = m_componentMetadata.getAttribute("public");
+ return (publicAttribute == null) || !publicAttribute.equalsIgnoreCase("false");
+ }
+
+ public String getComponentName() {
+ return m_componentName;
+ }
+
+ public String getComponentVersion() {
+ return m_componentVersion;
+ }
+
+ public String getExtension() {
+ return m_extension;
+ }
+
+ public Element getComponentMetadata() {
+ return m_componentMetadata;
+ }
+
+ public boolean isPublic() {
+ return visible;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java
new file mode 100644
index 0000000..5682f65
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java
@@ -0,0 +1,65 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.DeclarationBuilderService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * {@link org.osgi.framework.ServiceFactory} for {@link org.apache.felix.ipojo.extender.DeclarationBuilderService}.
+ * It avoids to explicitly gives a {@link org.osgi.framework.BundleContext} for each service method.
+ * The {@link org.osgi.framework.BundleContext} of the client is used.
+ */
+public class DeclarationServiceFactory implements ServiceFactory<DeclarationBuilderService> {
+
+ private final BundleContext bundleContext;
+ private ServiceRegistration<?> registration;
+
+ public DeclarationServiceFactory(final BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public void start() {
+ if (registration == null) {
+ registration = bundleContext.registerService(DeclarationBuilderService.class.getName(), this, null);
+ }
+ }
+
+ public void stop() {
+ if (registration != null) {
+ registration.unregister();
+ registration = null;
+ }
+ }
+
+ public DeclarationBuilderService getService(final Bundle bundle, final ServiceRegistration<DeclarationBuilderService> registration) {
+ return new DefaultDeclarationBuilderService(bundle.getBundleContext());
+ }
+
+ public void ungetService(final Bundle bundle, final ServiceRegistration<DeclarationBuilderService> registration, final DeclarationBuilderService service) {
+ // Nothing to do, built declarations will be kept
+ // It's the client responsibility to dispose its declarations
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java
new file mode 100644
index 0000000..ee3f823
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java
@@ -0,0 +1,60 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.ipojo.extender.ConfigurationBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+
+/**
+ * Declares a configuration and build the immutable {@link org.apache.felix.ipojo.extender.DeclarationHandle}
+ * containing that configuration.
+ */
+public class DefaultConfigurationBuilder implements ConfigurationBuilder {
+
+ private final DefaultInstanceBuilder builder;
+ private Map<String, Object> configuration = new Hashtable<String, Object>();
+
+ public DefaultConfigurationBuilder(final DefaultInstanceBuilder builder) {
+ this.builder = builder;
+ }
+
+ public ConfigurationBuilder property(final String name, final Object value) {
+ configuration.put(name, value);
+ return this;
+ }
+
+ public ConfigurationBuilder remove(final String name) {
+ configuration.remove(name);
+ return this;
+ }
+
+ public ConfigurationBuilder clear() {
+ configuration.clear();
+ return this;
+ }
+
+ public DeclarationHandle build() {
+ // Make a fresh dictionary instance, needed for immutable instance declarations
+ return builder.build(new Hashtable<String, Object>(configuration));
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java
new file mode 100644
index 0000000..a27ddbe
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java
@@ -0,0 +1,60 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationBuilderService;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultExtensionDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultTypeDeclaration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+public class DefaultDeclarationBuilderService implements DeclarationBuilderService {
+
+ private final BundleContext context;
+
+ public DefaultDeclarationBuilderService(final BundleContext context) {
+ this.context = context;
+ }
+
+ public InstanceBuilder newInstance(final String type) {
+ return newInstance(type, null);
+ }
+
+ public InstanceBuilder newInstance(final String type, final String name) {
+ return newInstance(type, name, null);
+ }
+
+ public InstanceBuilder newInstance(final String type, final String name, final String version) {
+ return new DefaultInstanceBuilder(context, type)
+ .version(version)
+ .name(name);
+ }
+
+ public DeclarationHandle newExtension(final String name, final FactoryBuilder builder) {
+ return new DefaultExtensionDeclaration(context, builder, name);
+ }
+
+ public DeclarationHandle newType(final Element description) {
+ return new DefaultTypeDeclaration(context, description);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java
new file mode 100644
index 0000000..d9d6655
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java
@@ -0,0 +1,114 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import static java.lang.String.format;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.ConfigurationBuilder;
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.osgi.framework.BundleContext;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 09:36
+ */
+public class DefaultInstanceBuilder implements InstanceBuilder {
+
+ private BundleContext context;
+ private String name;
+ private String type;
+ private String version;
+
+ public DefaultInstanceBuilder(final BundleContext context, final String type) {
+ this.context(context);
+ this.type(type);
+ }
+
+ public InstanceBuilder name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ public InstanceBuilder type(final String type) {
+ if (type == null) {
+ throw new IllegalArgumentException(format("'type' parameter cannot be null (instance must be of a given type)"));
+ }
+ this.type = type;
+ return this;
+ }
+
+ public InstanceBuilder type(final Class<?> type) {
+ if (type == null) {
+ throw new IllegalArgumentException(format("'type' parameter cannot be null (instance must be of a given type)"));
+ }
+ return type(type.getName());
+ }
+
+ public InstanceBuilder version(final String version) {
+ this.version = version;
+ return this;
+ }
+
+ public InstanceBuilder context(final BundleContext context) {
+ if (context == null) {
+ throw new IllegalArgumentException(format("'context' parameter cannot be null"));
+ }
+ this.context = context;
+ return this;
+ }
+
+ public ConfigurationBuilder configure() {
+ return new DefaultConfigurationBuilder(this);
+ }
+
+ /**
+ * Only called through ConfigurationBuilder to apply the created configuration to this instance
+ * @param configuration
+ */
+ public DeclarationHandle build(Dictionary<String, Object> configuration) {
+
+ // Prepare the instance configuration
+ if (configuration == null) {
+ configuration = new Hashtable<String, Object>();
+ }
+
+ if (name != null) {
+ configuration.put(Factory.INSTANCE_NAME_PROPERTY, name);
+ }
+
+ if (version != null) {
+ configuration.put(Factory.FACTORY_VERSION_PROPERTY, version);
+ }
+
+ return new DefaultInstanceDeclaration(context, type, configuration);
+
+ }
+
+ public DeclarationHandle build() {
+ return build(new Hashtable<String, Object>());
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinker.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinker.java
new file mode 100644
index 0000000..7630cea
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinker.java
@@ -0,0 +1,109 @@
+/*
+ * 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.extender.internal.linker;
+
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.internal.Lifecycle;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * The linker is responsible to bind extension declaration to type declaration.
+ * It tracks TypeDeclaration, and reifies them as factory.
+ */
+public class DeclarationLinker implements ServiceTrackerCustomizer, Lifecycle {
+ /**
+ * The bundle context. It uses the iPOJO bundle context.
+ */
+ private final BundleContext m_bundleContext;
+
+ /**
+ * The queue service on which we delegate the binding process.
+ */
+ private final QueueService m_queueService;
+
+ /**
+ * The service tracker looking for TypeDeclaration.
+ */
+ private final ServiceTracker m_typeTracker;
+
+ /**
+ * Creates the linker.
+ *
+ * @param bundleContext the bundle context
+ * @param queueService the queue service
+ */
+ public DeclarationLinker(BundleContext bundleContext, QueueService queueService) {
+ m_bundleContext = bundleContext;
+ m_queueService = queueService;
+ m_typeTracker = new ServiceTracker(m_bundleContext, TypeDeclaration.class.getName(), this);
+ }
+
+ /**
+ * When the iPOJO management starts, we look for type declaration.
+ */
+ public void start() {
+ m_typeTracker.open(true);
+ }
+
+ /**
+ * When iPOJO stops, we close the tracker.
+ */
+ public void stop() {
+ m_typeTracker.close();
+ }
+
+ /**
+ * A new type declaration was published.
+ *
+ * @param reference the service reference of the type declaration
+ * @return the managed type object wrapping the service object.
+ */
+ public Object addingService(ServiceReference reference) {
+ TypeDeclaration declaration = (TypeDeclaration) m_bundleContext.getService(reference);
+ ManagedType managedType = new ManagedType(reference.getBundle().getBundleContext(), m_queueService, declaration);
+ managedType.start();
+ return managedType;
+ }
+
+ /**
+ * Type declaration cannot be modified.
+ *
+ * @param reference the reference
+ * @param service the object returned by {@link #addingService(org.osgi.framework.ServiceReference)}
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Ignored
+ }
+
+ /**
+ * A type declaration service was withdrawn from the service registry.
+ *
+ * @param reference the leaving reference
+ * @param service the object returned by {@link #addingService(org.osgi.framework.ServiceReference)}
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ ManagedType managedType = (ManagedType) service;
+ managedType.stop();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/InstanceBundleContextAware.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/InstanceBundleContextAware.java
new file mode 100644
index 0000000..6307f56
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/InstanceBundleContextAware.java
@@ -0,0 +1,44 @@
+/*
+ * 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.extender.internal.linker;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Instance containers that can handle the bundle context from the instance declaration implement this interface,
+ * letting handlers and other entities to retrieve this bundle context.
+ * @since 1.11.2
+ */
+public interface InstanceBundleContextAware {
+
+ /**
+ * Sets the instance bundle context.
+ * @param context the context of the instance
+ * @since 1.11.2
+ */
+ public void setInstanceBundleContext(BundleContext context);
+
+ /**
+ * Gets the bundle context of the instance, i.e. the bundle context of the bundle having declared this instance.
+ * @return the bundle context of the instance.
+ * @since 1.11.2
+ */
+ public BundleContext getInstanceContext();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/ManagedType.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/ManagedType.java
new file mode 100644
index 0000000..12494f1
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/linker/ManagedType.java
@@ -0,0 +1,384 @@
+/*
+ * 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.extender.internal.linker;
+
+import static java.lang.String.format;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilderException;
+import org.apache.felix.ipojo.extender.internal.DefaultJob;
+import org.apache.felix.ipojo.extender.internal.Lifecycle;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * This class is responsible to create the factory for a given type declaration. It also instructs the factories to
+ * create
+ * the instance for each instance declaration targeting the managed factory.
+ */
+public class ManagedType implements FactoryStateListener, Lifecycle {
+ /**
+ * Identify the factory creation job submitted to the QueueService.
+ */
+ public static final String FACTORY_CREATION_JOB_TYPE = "factory.creation";
+ /**
+ * Identify the instance startup job submitted to the QueueService.
+ */
+ public static final String INSTANCE_STARTUP_JOB_TYPE = "instance.startup";
+ /**
+ * The bundle context
+ */
+ private final BundleContext m_bundleContext;
+ /**
+ * The queue service used for the creation.
+ */
+ private final QueueService m_queueService;
+ /**
+ * The type declaration that we have to handle.
+ */
+ private final TypeDeclaration m_declaration;
+ /**
+ * The service tracker tracking {@link ExtensionDeclaration} services.
+ */
+ private ServiceTracker m_extensionTracker;
+
+ /**
+ * The service tracker tracking the {@link InstanceDeclaration} services.
+ */
+ private ServiceTracker m_instanceTracker;
+
+ /**
+ * The job used to instantiate the factory.
+ */
+ private Future<IPojoFactory> m_future;
+
+ /**
+ * If the Managed Type cannot be initializes, sets this flag to true and no links will be created.
+ */
+ private boolean m_frozen;
+
+ /**
+ * Constructs a Managed Type object for the given type declaration.
+ *
+ * @param bundleContext the bundle context
+ * @param queueService the queue service
+ * @param declaration the declaration
+ */
+ public ManagedType(BundleContext bundleContext, QueueService queueService, TypeDeclaration declaration) {
+ m_bundleContext = bundleContext;
+ m_queueService = queueService;
+ m_declaration = declaration;
+ try {
+ initExtensionTracker();
+ initInstanceTracker();
+ } catch (InvalidSyntaxException e) {
+ // Error during filter creation, freeze the declaration and add a meaningful message
+ m_frozen = true;
+ m_declaration.unbind("Filter creation error", e);
+ }
+ }
+
+ /**
+ * Initializes the extension declaration tracker.
+ *
+ * @throws InvalidSyntaxException cannot happen
+ */
+ private void initExtensionTracker() throws InvalidSyntaxException {
+ String filter = format(
+ "(&(objectclass=%s)(%s=%s))",
+ ExtensionDeclaration.class.getName(),
+ ExtensionDeclaration.EXTENSION_NAME_PROPERTY,
+ m_declaration.getExtension()
+ );
+ m_extensionTracker = new ServiceTracker(m_bundleContext, m_bundleContext.createFilter(filter), new ExtensionSupport());
+ }
+
+ /**
+ * Initializes the instance declaration tracker.
+ *
+ * @throws InvalidSyntaxException cannot happen
+ */
+ private void initInstanceTracker() throws InvalidSyntaxException {
+
+ String filter;
+ String version = m_declaration.getComponentVersion();
+ if (version != null) {
+ // Track instance for:
+ // * this component's name OR classname
+ // AND
+ // * this component's version OR no version
+ filter = format(
+ "(&(objectClass=%s)(|(%s=%s)(%s=%s))(|(%s=%s)(!(%s=*))))",
+ InstanceDeclaration.class.getName(),
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ m_declaration.getComponentName(),
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ getComponentClassname(),
+ InstanceDeclaration.COMPONENT_VERSION_PROPERTY,
+ version,
+ InstanceDeclaration.COMPONENT_VERSION_PROPERTY
+ );
+ } else {
+ // Track instance for:
+ // * this component's name OR classname
+ // AND
+ // * no version
+ filter = format(
+ "(&(objectClass=%s)(|(%s=%s)(%s=%s))(!(%s=*)))",
+ InstanceDeclaration.class.getName(),
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ m_declaration.getComponentName(),
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ getComponentClassname(),
+ InstanceDeclaration.COMPONENT_VERSION_PROPERTY
+ );
+ }
+ m_instanceTracker = new ServiceTracker(m_bundleContext, m_bundleContext.createFilter(filter), new InstanceSupport());
+ }
+
+ /**
+ * Returns the {@literal classname} attribute value.
+ */
+ private String getComponentClassname() {
+ return m_declaration.getComponentMetadata().getAttribute("classname");
+ }
+
+ /**
+ * Starting the management.
+ * We open only the extension tracker.
+ */
+ public void start() {
+ if (!m_frozen) {
+ m_extensionTracker.open(true);
+ }
+ }
+
+ /**
+ * Stopping the management.
+ */
+ public void stop() {
+ m_instanceTracker.close();
+ m_extensionTracker.close();
+ }
+
+ /**
+ * The factory we have built has a state in his change.
+ *
+ * @param factory the changing factory
+ * @param newState the new factory state
+ */
+ public void stateChanged(Factory factory, int newState) {
+ if (Factory.VALID == newState) {
+ // Start tracking instances
+ m_instanceTracker.open(true);
+ } else {
+ // Un-track all instances
+ m_instanceTracker.close();
+ }
+ }
+
+ /**
+ * The service tracker customizer for extension declaration.
+ * It submits a factory building job when an extension matching our type declaration is found.
+ */
+ private class ExtensionSupport implements ServiceTrackerCustomizer {
+ public Object addingService(ServiceReference reference) {
+ final Object service = m_bundleContext.getService(reference);
+ if (service instanceof ExtensionDeclaration) {
+ m_future = m_queueService.submit(new DefaultJob<IPojoFactory>(reference.getBundle(), FACTORY_CREATION_JOB_TYPE) {
+
+ /**
+ * The factory creation job.
+ * @return the IPojoFactory
+ * @throws Exception the factory cannot be created
+ */
+ public IPojoFactory call() throws Exception {
+ ExtensionDeclaration declaration = (ExtensionDeclaration) service;
+ try {
+ // Build and start the factory instance
+ IPojoFactory factory = declaration.getFactoryBuilder().build(m_bundleContext, m_declaration.getComponentMetadata());
+ factory.addFactoryStateListener(ManagedType.this);
+ factory.start();
+
+ // Change the status
+ m_declaration.bind();
+
+ return factory;
+ } catch (FactoryBuilderException e) {
+ m_declaration.unbind(format("Cannot build '%s' factory instance", m_declaration.getExtension()), e);
+ } catch (Throwable t) {
+ m_declaration.unbind(format("Error during '%s' factory instance creation", m_declaration.getExtension()), t);
+ }
+
+ return null;
+ }
+ }, format("Building Factory for type %s", m_declaration.getComponentName()));
+ // Return something, otherwise, ServiceTracker think that we're not interested
+ // in this service and never call us back on disposal.
+ return service;
+ }
+
+ return null;
+ }
+
+ public void modifiedService(ServiceReference reference, Object o) {
+ }
+
+ public void removedService(ServiceReference reference, Object o) {
+
+ ExtensionDeclaration extensionDeclaration = (ExtensionDeclaration) o;
+ // Then stop the factory
+ try {
+ IPojoFactory factory = m_future.get();
+ // It is possible that the factory couldn't be created
+ if (factory != null) {
+ factory.removeFactoryStateListener(ManagedType.this);
+ factory.dispose();
+ m_declaration.unbind(format("Extension '%s' is missing",
+ extensionDeclaration.getExtensionName()));
+ }
+ } catch (InterruptedException e) {
+ m_declaration.unbind("Could not create Factory", e);
+ } catch (ExecutionException e) {
+ m_declaration.unbind("Factory creation throw an Exception", e);
+ }
+ m_future = null;
+ }
+ }
+
+ private class InstanceSupport implements ServiceTrackerCustomizer {
+ public Object addingService(final ServiceReference reference) {
+ Object service = m_bundleContext.getService(reference);
+ if (service instanceof InstanceDeclaration) {
+ final InstanceDeclaration instanceDeclaration = (InstanceDeclaration) service;
+
+ // Check that instance is not already bound
+ if (instanceDeclaration.getStatus().isBound()) {
+ return null;
+ }
+
+ // Handle visibility (private/public factories)
+ if (!m_declaration.isPublic()) {
+ if (!reference.getBundle().equals(m_bundleContext.getBundle())) {
+ Bundle origin = m_bundleContext.getBundle();
+ instanceDeclaration.unbind(
+ format("Component '%s/%s' is private. It only accept instances " +
+ "from bundle %s/%s [%d] (instance bundle origin: %d)",
+ m_declaration.getComponentName(),
+ m_declaration.getComponentVersion(),
+ origin.getSymbolicName(),
+ origin.getVersion(),
+ origin.getBundleId(),
+ reference.getBundle().getBundleId())
+ );
+ return null;
+ }
+ }
+
+ return m_queueService.submit(new DefaultJob<ComponentInstance>(reference.getBundle(), INSTANCE_STARTUP_JOB_TYPE) {
+ public ComponentInstance call() throws Exception {
+ try {
+ // Create the component's instance
+ // It is automatically started
+ // Future.get should never be null since this tracker is started when the factory has been created
+ ComponentInstance instance = m_future.get().createComponentInstance(instanceDeclaration.getConfiguration());
+ if (instance instanceof InstanceBundleContextAware) {
+ ((InstanceBundleContextAware) instance).setInstanceBundleContext(instanceDeclaration
+ .getBundle().getBundleContext());
+ }
+
+ // Notify the declaration that everything is fine
+ instanceDeclaration.bind();
+
+ return instance;
+ } catch (UnacceptableConfiguration c) {
+ instanceDeclaration.unbind(format("Instance configuration is invalid (component:%s/%s, bundle:%d)",
+ m_declaration.getComponentName(),
+ m_declaration.getComponentVersion(),
+ reference.getBundle().getBundleId()),
+ c);
+ } catch (MissingHandlerException e) {
+ instanceDeclaration.unbind(
+ format(
+ "Component '%s/%s' (required for instance creation) is missing some handlers",
+ m_declaration.getComponentName(),
+ m_declaration.getComponentVersion()
+ ),
+ e);
+ } catch (ConfigurationException e) {
+ instanceDeclaration.unbind(
+ format(
+ "Instance configuration is incorrect for component '%s/%s'",
+ m_declaration.getComponentName(),
+ m_declaration.getComponentVersion()),
+ e);
+ }
+
+ return null;
+ }
+ }, format("Creating component instance of type %s (declaration from bundle %d)",
+ m_declaration.getComponentName(),
+ reference.getBundle().getBundleId()));
+ }
+
+ return null;
+ }
+
+ public void modifiedService(ServiceReference reference, Object o) {
+ }
+
+ public void removedService(ServiceReference reference, Object o) {
+ InstanceDeclaration instanceDeclaration = (InstanceDeclaration) m_bundleContext.getService(reference);
+ Future<ComponentInstance> future = (Future<ComponentInstance>) o;
+ ComponentInstance instance;
+ try {
+ instance = future.get();
+ // It is possible that the instance couldn't be created
+ if (instance != null) {
+ String message = format("Factory for Component '%s/%s' is missing",
+ instance.getFactory().getName(),
+ m_declaration.getComponentVersion());
+ instanceDeclaration.unbind(message);
+
+ instance.stop();
+ instance.dispose();
+ }
+
+ } catch (InterruptedException e) {
+ instanceDeclaration.unbind("Could not create ComponentInstance", e);
+ } catch (ExecutionException e) {
+ instanceDeclaration.unbind("ComponentInstance creation throw an Exception", e);
+ }
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessor.java
new file mode 100644
index 0000000..1139928
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessor.java
@@ -0,0 +1,127 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.osgi.framework.Bundle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A bundle processor chaining others processor.
+ * It composes the <em>extender</em> mechanism.
+ * <p/>
+ * Instance must be created using the {@link #create(org.apache.felix.ipojo.extender.internal.BundleProcessor...)}
+ * method.
+ */
+public class ChainedBundleProcessor implements BundleProcessor {
+
+ /**
+ * The list of processors.
+ * Be aware that the order if important, as processors will be called in the insertion order.
+ * <p/>
+ * Once the chained bundle processor is created, this list cannot be modified.
+ */
+ private final List<BundleProcessor> m_processors = new ArrayList<BundleProcessor>();
+
+ private ChainedBundleProcessor() {
+ // Just here to avoid direct creation.
+ }
+
+ /**
+ * Creates a new chained bundle processor.
+ *
+ * @param processors the set of processor to chain. Cannot be <code>null</code> or empty.
+ * @return the created bundle processor
+ * @throws IllegalArgumentException if the given processor list is <code>null</code> or empty.
+ */
+ public static ChainedBundleProcessor create(BundleProcessor... processors) {
+ if (processors == null || processors.length == 0) {
+ throw new IllegalArgumentException("Chained processor cannot be created without processors");
+ }
+ ChainedBundleProcessor chain = new ChainedBundleProcessor();
+ Collections.addAll(chain.m_processors, processors);
+ return chain;
+ }
+
+ /**
+ * Gets the list of processors.
+ * This method returns a copy of the list of processor.
+ *
+ * @return a copy of the processor list
+ */
+ public List<BundleProcessor> getProcessors() {
+ List<BundleProcessor> list = new ArrayList<BundleProcessor>();
+ list.addAll(m_processors);
+ return list;
+ }
+
+ /**
+ * A bundle is starting.
+ * Call the {@link BundleProcessor#activate(org.osgi.framework.Bundle)} method on all chained processors.
+ *
+ * @param bundle the bundle
+ */
+ public void activate(Bundle bundle) {
+ for (BundleProcessor processor : m_processors) {
+ processor.activate(bundle);
+ }
+ }
+
+ /**
+ * A bundle is stopping.
+ * Call the {@link BundleProcessor#deactivate(org.osgi.framework.Bundle)} method on all chained processors.
+ *
+ * @param bundle the bundle
+ */
+ public void deactivate(Bundle bundle) {
+ List<BundleProcessor> reverse = new ArrayList<BundleProcessor>(m_processors);
+ Collections.reverse(reverse);
+ for (BundleProcessor processor : reverse) {
+ processor.deactivate(bundle);
+ }
+ }
+
+ /**
+ * The iPOJO bundle is starting.
+ * Call the {@link org.apache.felix.ipojo.extender.internal.BundleProcessor#start()} method on all chained
+ * processors.
+ */
+ public void start() {
+ for (BundleProcessor processor : m_processors) {
+ processor.start();
+ }
+ }
+
+ /**
+ * The iPOJO bundle is stopping.
+ * Call the {@link org.apache.felix.ipojo.extender.internal.BundleProcessor#stop()} method on all chained
+ * processors.
+ */
+ public void stop() {
+ List<BundleProcessor> reverse = new ArrayList<BundleProcessor>(m_processors);
+ Collections.reverse(reverse);
+ for (BundleProcessor processor : reverse) {
+ processor.stop();
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ComponentsBundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ComponentsBundleProcessor.java
new file mode 100644
index 0000000..066ce81
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ComponentsBundleProcessor.java
@@ -0,0 +1,231 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultTypeDeclaration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.Bundle;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Processor handling the {@link #IPOJO_HEADER} and {@link #IPOJO_HEADER_ALT}
+ * header from the bundle manifest.
+ */
+public class ComponentsBundleProcessor implements BundleProcessor {
+
+ /**
+ * iPOJO Component Type and Instance declaration header.
+ */
+ public static final String IPOJO_HEADER = "iPOJO-Components";
+
+ /**
+ * iPOJO Component Type and Instance declaration header
+ * (alternative).
+ * This header was introduced because of BND supporting only header
+ * starting with an uppercase.
+ */
+ public static final String IPOJO_HEADER_ALT = "IPOJO-Components";
+
+ /**
+ * The attribute used in instance configuration specifying the targeted component (i.e. factory).
+ */
+ public static final String COMPONENT_INSTANCE_ATTRIBUTE = "component";
+
+ /**
+ * The logger.
+ */
+ private final Log m_logger;
+
+ /**
+ * Registry storing the bundle to components and instances declared within this bundle.
+ */
+ private final Map<Bundle, ComponentsAndInstances> m_registry = new HashMap<Bundle, ComponentsAndInstances>();
+
+ /**
+ * Creates the component bundle processor.
+ *
+ * @param logger the logger.
+ */
+ public ComponentsBundleProcessor(Log logger) {
+ m_logger = logger;
+ }
+
+ /**
+ * A bundle is starting.
+ *
+ * @param bundle the bundle
+ */
+ public void activate(Bundle bundle) {
+ Dictionary dict = bundle.getHeaders();
+ // Check bundle
+ String header = (String) dict.get(IPOJO_HEADER);
+ // Check the alternative header
+ if (header == null) {
+ header = (String) dict.get(IPOJO_HEADER_ALT);
+ }
+
+ if (header != null) {
+ try {
+ parse(bundle, header);
+ } catch (IOException e) {
+ m_logger.log(Logger.ERROR, "An exception occurs during the parsing of the bundle " + bundle.getBundleId(), e);
+ } catch (ParseException e) {
+ m_logger.log(Logger.ERROR, "A parse exception occurs during the parsing of the bundle " + bundle.getBundleId(), e);
+ }
+ }
+
+ }
+
+ /**
+ * A bundle is stopping.
+ *
+ * @param bundle the bundle
+ */
+ public void deactivate(Bundle bundle) {
+ ComponentsAndInstances cai = m_registry.remove(bundle);
+ if (cai != null) {
+ cai.stop();
+ }
+ }
+
+ /**
+ * {@inheritDoc BundleProcessor#start}
+ */
+ public void start() {
+ // Nothing to do
+ }
+
+ /**
+ * {@inheritDoc BundleProcessor#stop}
+ * <p/>
+ * This method cleans up all created factories and instances.
+ */
+ public void stop() {
+ // Ignored, for a simple ordered shutdown, use ReverseBundleProcessor
+ }
+
+ /**
+ * Parses the internal metadata (from the manifest
+ * (in the iPOJO-Components property)). This methods
+ * creates factories and add instances to the instance creator.
+ *
+ * @param bundle the owner bundle.
+ * @param components The iPOJO Header String.
+ * @throws IOException if the manifest can not be found
+ * @throws ParseException if the parsing process failed
+ */
+ private void parse(Bundle bundle, String components) throws IOException, ParseException {
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.parseHeader(components);
+
+ // Get the component type declaration
+ Element[] metadata = parser.getComponentsMetadata();
+ for (int i = 0; i < metadata.length; i++) {
+ handleTypeDeclaration(bundle, metadata[i]);
+ }
+
+ Dictionary[] instances = parser.getInstances();
+ for (int i = 0; instances != null && i < instances.length; i++) {
+ handleInstanceDeclaration(bundle, instances[i]);
+ }
+ }
+
+ /**
+ * Extracts and builds the declaration attached to an instance.
+ *
+ * @param bundle the bundle declaring the instance
+ * @param instance the instance configuration (parsed from the header)
+ */
+ private void handleInstanceDeclaration(Bundle bundle, Dictionary instance) {
+
+ String component = (String) instance.get(COMPONENT_INSTANCE_ATTRIBUTE);
+ //String v = (String) instance.get(Factory.FACTORY_VERSION_PROPERTY); //TODO CES to GSA, why this is commented ?
+
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(bundle.getBundleContext(),
+ component, instance);
+ declaration.start();
+
+ getComponentsAndInstances(bundle).m_instances.add(declaration);
+
+ }
+
+ /**
+ * Adds a component factory to the factory list.
+ *
+ * @param metadata the new component metadata.
+ * @param bundle the bundle.
+ */
+ private void handleTypeDeclaration(Bundle bundle, Element metadata) {
+
+ DefaultTypeDeclaration declaration = new DefaultTypeDeclaration(bundle.getBundleContext(), metadata);
+ declaration.start();
+
+ getComponentsAndInstances(bundle).m_types.add(declaration);
+
+ }
+
+ /**
+ * Gets the {@link ComponentsAndInstances} declared by the given bundle.
+ *
+ * @param bundle the bundle
+ * @return the set of component and instances declared by the bundle, <code>null</code> otherwise
+ */
+ private ComponentsAndInstances getComponentsAndInstances(Bundle bundle) {
+ ComponentsAndInstances cai = m_registry.get(bundle);
+ if (cai == null) {
+ cai = new ComponentsAndInstances();
+ m_registry.put(bundle, cai);
+ }
+ return cai;
+ }
+
+ /**
+ * Container storing the components and instances declared by a bundle.
+ * This class is not intended to be used outside from the current processor.
+ */
+ private static class ComponentsAndInstances {
+ List<DefaultTypeDeclaration> m_types = new ArrayList<DefaultTypeDeclaration>();
+ List<DefaultInstanceDeclaration> m_instances = new ArrayList<DefaultInstanceDeclaration>();
+
+ /**
+ * Stops all declarations.
+ */
+ void stop() {
+ for (DefaultInstanceDeclaration instance : m_instances) {
+ instance.stop();
+ }
+ for (DefaultTypeDeclaration declaration : m_types) {
+ declaration.stop();
+ }
+ m_instances.clear();
+ m_types.clear();
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationAnnotationScanner.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationAnnotationScanner.java
new file mode 100644
index 0000000..b537e47
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationAnnotationScanner.java
@@ -0,0 +1,71 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.configuration.Configuration;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Class visitor detecting @Configuration annotation.
+ * <p/>
+ * After the visit, two state variables are set:
+ * {@literal isConfiguration} is set to true if the class contained the @Configuration annotation
+ * {@literal parent} is set to the parent class if and only if it's not a java.* class (which don't contain the
+ * Configuration annotation) and {@literal isConfiguration} is set to false
+ */
+public class ConfigurationAnnotationScanner extends ClassVisitor implements Opcodes {
+
+ private static final String CONFIGURATION_ANNOTATION_DESCRIPTOR = Type.getType(Configuration.class)
+ .getDescriptor();
+ private boolean m_isConfiguration = false;
+ private String m_super;
+
+ public ConfigurationAnnotationScanner() {
+ super(Opcodes.ASM5);
+ }
+
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ m_super = superName; // This is the internal class name.
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean vis) {
+ if (desc.equals(CONFIGURATION_ANNOTATION_DESCRIPTOR)) {
+ m_isConfiguration = true;
+ }
+ return null;
+ }
+
+ public boolean isConfiguration() {
+ return m_isConfiguration;
+ }
+
+ public String getParent() {
+ if (m_super == null || m_super.startsWith("java/") || m_isConfiguration) {
+ return null;
+ }
+ return m_super.replace("/", ".");
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationProcessor.java
new file mode 100644
index 0000000..7ec25a6
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ConfigurationProcessor.java
@@ -0,0 +1,331 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.configuration.Instance;
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.apache.felix.ipojo.extender.internal.Extender;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultTypeDeclaration;
+import org.apache.felix.ipojo.util.InvocationResult;
+import org.apache.felix.ipojo.util.Log;
+import org.objectweb.asm.ClassReader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.wiring.BundleWiring;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.*;
+
+import static org.apache.felix.ipojo.util.Reflection.fields;
+import static org.apache.felix.ipojo.util.Reflection.methods;
+import static org.apache.felix.ipojo.util.StreamUtils.closeQuietly;
+
+/**
+ * Processor looking for classes annotated with @Configuration and creating the corresponding instance declaration.
+ */
+public class ConfigurationProcessor implements BundleProcessor {
+
+ /**
+ * The logger.
+ */
+ private final Log m_logger;
+
+ /**
+ * Registry storing the bundle to components and instances declared within this bundle.
+ * Only instances are expected.
+ */
+ private final Map<Bundle, ComponentsAndInstances> m_registry = new HashMap<Bundle, ComponentsAndInstances>();
+
+ /**
+ * Set to false to disable this processor.
+ * When an OSGi framework does not provide the wiring API, this processor is disabled.
+ */
+ private final boolean m_enabled;
+
+ /**
+ * Creates the configuration processor.
+ *
+ * @param logger the logger.
+ */
+ public ConfigurationProcessor(Log logger) {
+
+ m_logger = logger;
+
+ // org.osgi.framework.wiring may not be available, in this case, disable us.
+ try {
+ this.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
+ } catch (ClassNotFoundException e) {
+ m_logger.log(Log.ERROR, "The org.osgi.framework.wiring.BundleWiring class is not provided by the " +
+ "framework, configuration processor disabled.");
+ m_enabled = false;
+ return;
+ }
+ // Check ok.
+ m_enabled = true;
+ }
+
+ public static String getClassNameFromResource(String resource) {
+ String res = resource;
+ if (resource.startsWith("/")) {
+ res = resource.substring(1); // Remove the first /
+ }
+ res = res.substring(0, res.length() - ".class".length()); // Remove the .class
+ return res.replace("/", ".");
+ }
+
+ /**
+ * A bundle is starting.
+ *
+ * @param bundle the bundle
+ */
+ public void activate(Bundle bundle) {
+ if (! m_enabled && Extender.getIPOJOBundleContext().getBundle().getBundleId() == bundle.getBundleId()) {
+ // Fast return if the configuration tracking is disabled, or if we are iPOJO
+ return;
+ }
+
+ // It's not required to process bundle not importing the configuration package.
+ final String imports = bundle.getHeaders().get(Constants.IMPORT_PACKAGE);
+ if (imports == null || ! imports.contains("org.apache.felix.ipojo.configuration")) {
+ // TODO Check dynamic imports to verify if the package is not imported lazily.
+ return;
+ }
+
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ if (wiring == null) {
+ // Invalid state.
+ m_logger.log(Log.ERROR, "The bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ") " +
+ "cannot be adapted to BundleWiring, state: " + bundle.getState());
+ return;
+ }
+
+ // Only lookup for local classes, parent classes will be analyzed on demand.
+ Collection<String> resources = wiring.listResources("/", "*.class",
+ BundleWiring.FINDENTRIES_RECURSE + BundleWiring.LISTRESOURCES_LOCAL);
+ if (resources == null) {
+ m_logger.log(Log.ERROR, "The bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ") " +
+ " does not have any classes to be analyzed");
+ return;
+ }
+ m_logger.log(Log.DEBUG, resources.size() + " classes found");
+ handleResources(bundle, resources, wiring.getClassLoader());
+ }
+
+ /**
+ * A bundle is stopping.
+ *
+ * @param bundle the bundle
+ */
+ public void deactivate(Bundle bundle) {
+ if (! m_enabled) { return; }
+
+ ComponentsAndInstances cai = m_registry.remove(bundle);
+ if (cai != null) {
+ cai.stop();
+ }
+ }
+
+ /**
+ * {@inheritDoc BundleProcessor#start}
+ */
+ public void start() {
+ // Nothing to do
+ }
+
+ /**
+ * {@inheritDoc BundleProcessor#stop}
+ * <p/>
+ * This method cleans up all created factories and instances.
+ */
+ public void stop() {
+ // Ignored, for a simple ordered shutdown, use ReverseBundleProcessor
+ }
+
+ private void handleResources(Bundle bundle, Collection<String> resources, ClassLoader classLoader) {
+ for (String resource : resources) {
+ handleResource(bundle, resource, classLoader);
+ }
+ }
+
+ private void handleResource(Bundle bundle, String resource, ClassLoader classLoader) {
+ URL url = classLoader.getResource(resource);
+ if (url == null) {
+ m_logger.log(Log.ERROR, "The resource " + resource + " cannot be loaded by " + bundle.getBundleId() + " " +
+ "(" + bundle.getSymbolicName() + ")");
+ return;
+ }
+
+ try {
+ if (hasConfigurationAnnotation(bundle, url, classLoader)) {
+ instantiateAndDeclareInstances(bundle, resource, classLoader);
+ }
+ } catch (IOException e) {
+ m_logger.log(Log.ERROR, "The resource " + resource + " cannot be loaded by " + bundle.getBundleId() + " " +
+ "(" + bundle.getSymbolicName() + ")", e);
+ }
+
+ }
+
+ private void instantiateAndDeclareInstances(Bundle bundle, String resource, ClassLoader classLoader) {
+ String classname = getClassNameFromResource(resource);
+ List<Instance> instances = new ArrayList<Instance>();
+ try {
+ Class clazz = classLoader.loadClass(classname);
+ Object configuration = clazz.newInstance();
+
+ // Collect fields
+ Map<Field, Instance> fields =
+ fields().ofType(Instance.class).in(configuration).map();
+ for (Map.Entry<Field, Instance> entry : fields.entrySet()) {
+ Instance instance = entry.getValue();
+ instance.nameIfUnnamed(entry.getKey().getName())
+ .with("instance.bundle.context").setto(bundle.getBundleContext());
+ instances.add(instance);
+ }
+
+ // Collect methods with Bundle Context as argument
+ Map<Method, InvocationResult<Instance>> methods =
+ methods().in(configuration).ofReturnType(Instance.class).withParameter(BundleContext.class)
+ .map(bundle.getBundleContext());
+
+ // Collect methods without arguments
+ methods.putAll(methods().in(configuration).ofReturnType(Instance.class).map());
+
+ for (Map.Entry<Method, InvocationResult<Instance>> entry : methods.entrySet()) {
+ Instance instance = entry.getValue().get();
+ if (instance == null) {
+ m_logger.log(Log.ERROR, "The Instance declaration creation failed because the method " + entry
+ .getKey().getName() + " of class " + entry.getKey().getDeclaringClass() + " threw an " +
+ "exception", entry.getValue().error());
+ } else {
+ instance
+ .nameIfUnnamed(entry.getKey().getName())
+ .with("instance.bundle.context").setto(bundle.getBundleContext());
+ instances.add(instance);
+ }
+ }
+
+ } catch (ClassNotFoundException e) {
+ m_logger.log(Log.ERROR, "Cannot load class " + classname + " despite it was considered as a " +
+ "configuration", e);
+ return;
+ } catch (InstantiationException e) {
+ m_logger.log(Log.ERROR, "Cannot instantiate class " + classname + " despite it was considered as a " +
+ "configuration", e);
+ return;
+ } catch (IllegalAccessException e) {
+ m_logger.log(Log.ERROR, "Cannot instantiate class " + classname + " despite it was considered as a " +
+ "configuration", e);
+ return;
+ }
+
+ m_logger.log(Log.WARNING, instances.size() + " instances found in class " + classname);
+ //Build and enqueue declaration
+ for (Instance instance : instances) {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(bundle.getBundleContext(),
+ instance.factory(), instance.configuration());
+ declaration.start();
+ getComponentsAndInstances(bundle).m_instances.add(declaration);
+ }
+ }
+
+ private boolean hasConfigurationAnnotation(Bundle bundle, URL url, ClassLoader classLoader) throws IOException {
+ InputStream is = url.openStream();
+
+ try {
+ // Exclude inner classes and classes containing $
+ if (url.toExternalForm().contains("$")) {
+ return false;
+ }
+
+ ClassReader reader = new ClassReader(is);
+ ConfigurationAnnotationScanner scanner = new ConfigurationAnnotationScanner();
+ reader.accept(scanner, 0);
+
+ // Only class with the @Configuration are considered, parent classes are not analyzed.
+ // Indeed, we have to detect when the parent must be considered independently,
+ // or when only the daughter needs too (to avoid creating the instances twice).
+
+ return scanner.isConfiguration();
+
+ // The following code would traverse the whole class hierarchy.
+// if (scanner.isConfiguration()) {
+// return true;
+// } else if (scanner.getParent() != null) {
+// URL parentUrl = classLoader.getResource("/" + scanner.getParent().replace(".", "/") + ".class");
+// if (parentUrl == null) {
+// m_logger.log(Log.DEBUG, "Cannot load the parent class " + scanner.getParent() + " - stopping " +
+// "scan");
+// return false;
+// }
+// return hasConfigurationAnnotation(bundle, parentUrl, classLoader);
+// }
+ } finally {
+ closeQuietly(is);
+ }
+ }
+
+ /**
+ * Gets the {@link ComponentsAndInstances} declared by the given bundle.
+ *
+ * @param bundle the bundle
+ * @return the set of component and instances declared by the bundle, <code>null</code> otherwise
+ */
+ private ComponentsAndInstances getComponentsAndInstances(Bundle bundle) {
+ ComponentsAndInstances cai = m_registry.get(bundle);
+ if (cai == null) {
+ cai = new ComponentsAndInstances();
+ m_registry.put(bundle, cai);
+ }
+ return cai;
+ }
+
+ /**
+ * Container storing the components and instances declared by a bundle.
+ * This class is not intended to be used outside from the current processor.
+ */
+ private static class ComponentsAndInstances {
+ List<DefaultTypeDeclaration> m_types = new ArrayList<DefaultTypeDeclaration>();
+ List<DefaultInstanceDeclaration> m_instances = new ArrayList<DefaultInstanceDeclaration>();
+
+ /**
+ * Stops all declarations.
+ */
+ void stop() {
+ for (DefaultInstanceDeclaration instance : m_instances) {
+ instance.stop();
+ }
+ for (DefaultTypeDeclaration declaration : m_types) {
+ declaration.stop();
+ }
+ m_instances.clear();
+ m_types.clear();
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessor.java
new file mode 100644
index 0000000..b9f4e6b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessor.java
@@ -0,0 +1,176 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.apache.felix.ipojo.extender.internal.builder.ReflectiveFactoryBuilder;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultExtensionDeclaration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.util.*;
+
+/**
+ * Bundle processor handling the {@link #IPOJO_EXTENSION} header.
+ */
+public class ExtensionBundleProcessor implements BundleProcessor {
+
+ /**
+ * iPOJO Extension declaration header.
+ */
+ public static final String IPOJO_EXTENSION = "IPOJO-Extension";
+
+ /**
+ * Logger.
+ */
+ private final Log m_logger;
+
+ /**
+ * The map storing the association between bundles and the list of extension declaration.
+ */
+ private Map<Bundle, List<DefaultExtensionDeclaration>> m_extensions = new HashMap<Bundle, List<DefaultExtensionDeclaration>>();
+
+ /**
+ * Creates the processor.
+ *
+ * @param logger the logger
+ */
+ public ExtensionBundleProcessor(Log logger) {
+ m_logger = logger;
+ }
+
+ /**
+ * A bundle is starting.
+ *
+ * @param bundle the bundle
+ */
+ public void activate(Bundle bundle) {
+ Dictionary dict = bundle.getHeaders();
+ // Check for abstract factory type
+ String extension = (String) dict.get(IPOJO_EXTENSION);
+ if (extension != null) {
+ activateExtensions(bundle, extension);
+ }
+ }
+
+ /**
+ * A bundle is stopping.
+ *
+ * @param bundle the bundle
+ */
+ public void deactivate(Bundle bundle) {
+ List<DefaultExtensionDeclaration> declarations = m_extensions.get(bundle);
+ if (declarations != null) {
+ for (DefaultExtensionDeclaration declaration : declarations) {
+ declaration.stop();
+ }
+ m_extensions.remove(bundle);
+ }
+ }
+
+ /**
+ * iPOJO is starting.
+ * Nothing to do.
+ */
+ public void start() {
+ // Nothing to do
+ }
+
+ /**
+ * iPOJO is stopping.
+ * We clean up all extension in the reverse order of their installation.
+ */
+ public void stop() {
+ // Construct a new instance to avoid ConcurrentModificationException since deactivate also change the extensions
+ // list
+ // Ignored, for a simple ordered shutdown, use ReverseBundleProcessor
+ }
+
+ /**
+ * Parses an IPOJO-Extension manifest header and then creates
+ * iPOJO extensions (factory types).
+ *
+ * @param bundle the bundle containing the header.
+ * @param header the header to parse.
+ */
+ private void activateExtensions(Bundle bundle, String header) {
+ String[] extensions = ParseUtils.split(header, ",");
+ for (int i = 0; extensions != null && i < extensions.length; i++) {
+ String[] segments = ParseUtils.split(extensions[i], ":");
+
+ /*
+ * Get the fully qualified type name.
+ * type = [namespace] name
+ */
+ String[] nameparts = ParseUtils.split(segments[0].trim(), " \t");
+ String type = nameparts.length == 1 ? nameparts[0] : nameparts[0] + ":" + nameparts[1];
+ String classname = segments[1];
+
+ Class<? extends IPojoFactory> clazz;
+ try {
+ clazz = bundle.loadClass(classname).asSubclass(IPojoFactory.class);
+ } catch (ClassNotFoundException e) {
+ String message = String.format("Cannot load class '%s' from bundle %s (%s) for extension '%s'",
+ classname,
+ bundle.getSymbolicName(),
+ bundle.getVersion(),
+ type);
+ m_logger.log(Logger.ERROR, message, e);
+ return;
+ }
+
+ try {
+ ReflectiveFactoryBuilder builder = new ReflectiveFactoryBuilder(clazz.getConstructor(BundleContext.class, Element.class));
+ DefaultExtensionDeclaration declaration = new DefaultExtensionDeclaration(bundle.getBundleContext(), builder, type);
+
+ getBundleDeclarations(bundle).add(declaration);
+
+ declaration.start();
+
+ m_logger.log(Logger.DEBUG, "New factory type available: " + type);
+ } catch (NoSuchMethodException e) {
+ m_logger.log(Logger.ERROR,
+ String.format("Extension '%s' is missing the required (BundleContext, Element) public " +
+ "constructor", clazz.getName()));
+ }
+ }
+ }
+
+ /**
+ * Gets the list of declaration for the given method.
+ *
+ * @param bundle the bundle
+ * @return the list of extension declaration associated to the given bundle, <code>null</code> otherwise.
+ */
+ private List<DefaultExtensionDeclaration> getBundleDeclarations(Bundle bundle) {
+ List<DefaultExtensionDeclaration> declarations = m_extensions.get(bundle);
+ if (declarations == null) {
+ declarations = new ArrayList<DefaultExtensionDeclaration>();
+ m_extensions.put(bundle, declarations);
+ }
+ return declarations;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ForwardingBundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ForwardingBundleProcessor.java
new file mode 100644
index 0000000..f11d7e1
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ForwardingBundleProcessor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.osgi.framework.Bundle;
+
+/**
+ * A bundle processor delegating to a wrapped processor.
+ * Implementation defined how we retrieve the delegate.
+ */
+public abstract class ForwardingBundleProcessor implements BundleProcessor {
+ /**
+ * Implementation must implement this method to retrieve the wrapped bundle processor.
+ *
+ * @return the wrapped bundle processor on which we delegate all calls.
+ */
+ protected abstract BundleProcessor delegate();
+
+ public void activate(Bundle bundle) {
+ delegate().activate(bundle);
+ }
+
+ public void deactivate(Bundle bundle) {
+ delegate().deactivate(bundle);
+ }
+
+ public void start() {
+ delegate().start();
+ }
+
+ public void stop() {
+ delegate().stop();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/QueuingActivationProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/QueuingActivationProcessor.java
new file mode 100644
index 0000000..700ec34
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/QueuingActivationProcessor.java
@@ -0,0 +1,83 @@
+/*
+ * 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.extender.internal.processor;
+
+import static java.lang.String.format;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.apache.felix.ipojo.extender.internal.DefaultJob;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.Bundle;
+
+/**
+ * A bundle processor submitting the activating job to the queue service.
+ * The submitted job relies on a delegated bundle processor.
+ */
+public class QueuingActivationProcessor extends ForwardingBundleProcessor {
+
+ /**
+ * Identify the kind of job submitted to the QueueService.
+ */
+ public static final String BUNDLE_ACTIVATION_JOB_TYPE = "bundle.activation";
+
+ /**
+ * The wrapped bundle processor used by the job.
+ */
+ private final BundleProcessor m_delegate;
+
+ /**
+ * The queue service.
+ */
+ private final QueueService m_queueService;
+
+ /**
+ * Creates an instance of the queuing bundle processor
+ *
+ * @param delegate the bundle processor used by the submitted job
+ * @param queueService the used queue service
+ */
+ public QueuingActivationProcessor(BundleProcessor delegate, QueueService queueService) {
+ m_delegate = delegate;
+ m_queueService = queueService;
+ }
+
+ @Override
+ protected BundleProcessor delegate() {
+ return m_delegate;
+ }
+
+ /**
+ * A bundle is starting.
+ * The processing of the bundle is wrapped in a job submitted to the queue service.
+ *
+ * @param bundle the bundle
+ */
+ public void activate(final Bundle bundle) {
+ m_queueService.submit(
+ new DefaultJob<Boolean>(bundle, BUNDLE_ACTIVATION_JOB_TYPE) {
+ public Boolean call() throws Exception {
+ QueuingActivationProcessor.super.activate(bundle);
+ return true;
+ }
+ },
+ format("Bundle %d being activated", bundle.getBundleId()));
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessor.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessor.java
new file mode 100644
index 0000000..92dea17
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessor.java
@@ -0,0 +1,96 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.osgi.framework.Bundle;
+
+import java.util.LinkedList;
+
+/**
+ * A bundle processor delegating a wrapped bundle processor. On stop, the bundles are processed in reverse.
+ */
+public class ReverseBundleProcessor extends ForwardingBundleProcessor {
+
+ /**
+ * The wrapped bundle processor.
+ */
+ private final BundleProcessor m_delegate;
+
+ /**
+ * A list of bundle to process.
+ */
+ private LinkedList<Bundle> m_bundles = new LinkedList<Bundle>();
+
+ /**
+ * Creates the processor.
+ *
+ * @param delegate the processor on which call are delegated
+ */
+ public ReverseBundleProcessor(BundleProcessor delegate) {
+ m_delegate = delegate;
+ }
+
+ /**
+ * @return the wrapped processor.
+ */
+ @Override
+ protected BundleProcessor delegate() {
+ return m_delegate;
+ }
+
+ /**
+ * A bundle is starting.
+ * The bundle is added to the list, and the processing delegated to the wrapped processor.
+ *
+ * @param bundle the bundle
+ */
+ @Override
+ public void activate(Bundle bundle) {
+ m_bundles.addLast(bundle);
+ super.activate(bundle);
+ }
+
+ /**
+ * A bundle is stopping.
+ * The bundle is removed from the list and the processing delegated to the wrapped processor.
+ *
+ * @param bundle the bundle
+ */
+ @Override
+ public void deactivate(Bundle bundle) {
+ m_bundles.remove(bundle);
+ super.deactivate(bundle);
+ }
+
+ /**
+ * iPOJO is stopping.
+ * The bundle that are still in the list are processed in the <strong>reverse</strong> order by the wrapped
+ * processor.
+ */
+ @Override
+ public void stop() {
+ // deactivate in reverse order
+ while (!m_bundles.isEmpty()) {
+ super.deactivate(m_bundles.removeLast());
+ }
+ super.stop();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueService.java
new file mode 100644
index 0000000..c5e6b58
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueService.java
@@ -0,0 +1,86 @@
+/*
+ * 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.extender.internal.queue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.extender.internal.AbstractService;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.BundleContext;
+
+/**
+ * User: guillaume
+ * Date: 01/10/13
+ * Time: 14:41
+ */
+public abstract class AbstractQueueService extends AbstractService implements QueueService, QueueNotifier {
+
+ /**
+ * Store QueueListeners.
+ */
+ protected final List<QueueListener> m_listeners = new ArrayList<QueueListener>();
+
+ /**
+ * Constructor.
+ *
+ * @param bundleContext the bundle context
+ * @param type the specification
+ */
+ protected AbstractQueueService(final BundleContext bundleContext, final Class<?> type) {
+ super(bundleContext, type);
+ }
+
+ public void addQueueListener(final QueueListener listener) {
+ m_listeners.add(listener);
+ }
+
+ public void removeQueueListener(final QueueListener listener) {
+ m_listeners.remove(listener);
+ }
+
+ public void fireEnlistedJobInfo(JobInfo info) {
+ for (QueueListener listener : m_listeners) {
+ listener.enlisted(info);
+ }
+ }
+
+ public void fireStartedJobInfo(JobInfo info) {
+ for (QueueListener listener : m_listeners) {
+ listener.started(info);
+ }
+ }
+
+ public void fireExecutedJobInfo(JobInfo info, Object result) {
+ for (QueueListener listener : m_listeners) {
+ listener.executed(info, result);
+ }
+ }
+
+ public void fireFailedJobInfo(JobInfo info, Throwable throwable) {
+ for (QueueListener listener : m_listeners) {
+ listener.failed(info, throwable);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueService.java
new file mode 100644
index 0000000..3334f4a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueService.java
@@ -0,0 +1,250 @@
+/*
+ * 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.extender.internal.queue;
+
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * An asynchronous implementation of the queue service. This implementation relies on an executor service.
+ */
+public class ExecutorQueueService extends AbstractQueueService implements LifecycleQueueService, ManagedService {
+
+ /**
+ * Property name used to configure this ThreadPool's size (usable as System Property or ConfigAdmin property).
+ */
+ public static final String THREADPOOL_SIZE_PROPERTY = "org.apache.felix.ipojo.extender.ThreadPoolSize";
+
+ /**
+ * Service PID used to identify service with ConfigAdmin.
+ */
+ public static final String EXECUTOR_QUEUE_SERVICE_PID = "org.apache.felix.ipojo.extender.ExecutorQueueService";
+
+ /**
+ * The default thread pool size (3).
+ */
+ private final static int DEFAULT_QUEUE_SIZE = 3;
+
+ /**
+ * The executor service.
+ */
+ private final ThreadPoolExecutor m_executorService;
+
+ /**
+ * The statistics populated by this queue service.
+ */
+ private final Statistic m_statistic = new Statistic();
+
+ /**
+ * Store service properties (used when updating their values)
+ */
+ private Hashtable<String, Object> m_properties;
+
+ /**
+ * Initial thread pool size.
+ */
+ private final int initialSize;
+
+ /**
+ * Creates the queue service using the default pool size.
+ *
+ * @param bundleContext the bundle context.
+ */
+ public ExecutorQueueService(BundleContext bundleContext) {
+ this(bundleContext, DEFAULT_QUEUE_SIZE);
+ }
+
+ /**
+ * Creates the queue service.
+ *
+ * @param bundleContext the bundle context.
+ * @param size the thread pool size.
+ */
+ public ExecutorQueueService(BundleContext bundleContext, int size) {
+ this(bundleContext, (ThreadPoolExecutor) Executors.newFixedThreadPool(size));
+ }
+
+ /**
+ * Creates the queue service.
+ *
+ * @param bundleContext the bundle context.
+ * @param size the thread pool size
+ * @param threadFactory the thread factory
+ */
+ public ExecutorQueueService(BundleContext bundleContext, int size, ThreadFactory threadFactory) {
+ this(bundleContext, (ThreadPoolExecutor) Executors.newFixedThreadPool(size, threadFactory));
+ }
+
+
+ /**
+ * Creates the queue service.
+ * All others constructors delegates to this one.
+ *
+ * @param bundleContext the bundle context
+ * @param executorService the executor service we have to use
+ */
+ private ExecutorQueueService(BundleContext bundleContext, ThreadPoolExecutor executorService) {
+ super(bundleContext, QueueService.class);
+ m_executorService = executorService;
+ initialSize = executorService.getCorePoolSize();
+ m_properties = getDefaultProperties();
+ }
+
+ @Override
+ protected ServiceRegistration<?> registerService() {
+ // Register the instance under QueueService and ManagedService types
+ return getBundleContext().registerService(new String[] {QueueService.class.getName(), ManagedService.class.getName()},
+ this,
+ getServiceProperties());
+ }
+
+ /**
+ * Stops the service.
+ */
+ public void stop() {
+ m_executorService.shutdown();
+ // Wait for potential executed tasks to finish their executions
+ try {
+ m_executorService.awaitTermination(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // Ignored
+ }
+ super.stop();
+ }
+
+ @Override
+ protected Dictionary<String, ?> getServiceProperties() {
+ return m_properties;
+ }
+
+ private Hashtable<String, Object> getDefaultProperties() {
+ Hashtable<String, Object> initial = new Hashtable<String, Object>();
+ initial.put(Constants.SERVICE_PID, EXECUTOR_QUEUE_SERVICE_PID);
+ initial.put(QueueService.QUEUE_MODE_PROPERTY, QueueService.ASYNCHRONOUS_QUEUE_MODE);
+ initial.put(THREADPOOL_SIZE_PROPERTY, initialSize);
+ return initial;
+ }
+
+ public int getFinished() {
+ return m_statistic.getFinishedCounter().get();
+ }
+
+ public int getWaiters() {
+ return m_statistic.getWaiters().size();
+ }
+
+ public int getCurrents() {
+ return m_statistic.getCurrentsCounter().get();
+ }
+
+ public List<JobInfo> getWaitersInfo() {
+ List<JobInfo> snapshot;
+ synchronized (m_statistic.getWaiters()) {
+ snapshot = new ArrayList<JobInfo>(m_statistic.getWaiters());
+ }
+ return Collections.unmodifiableList(snapshot);
+ }
+
+ /**
+ * Submits a job to the queue. The submitted job is wrapped into a {@link JobInfoCallable} to collect the
+ * statistics.
+ *
+ * @param callable the job
+ * @param callback callback called when the job is processed
+ * @param description a description of the job
+ * @return the reference on the submitted job
+ */
+ public <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description) {
+ JobInfoCallable<T> task = new JobInfoCallable<T>(this, m_statistic, callable, callback, description);
+ return m_executorService.submit(task);
+ }
+
+ public <T> Future<T> submit(Job<T> callable, String description) {
+ return submit(callable, null, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable) {
+ return submit(callable, "No description");
+ }
+
+ public void updated(Dictionary properties) throws ConfigurationException {
+
+ // Default configuration
+ if (properties == null) {
+ properties = getDefaultProperties();
+ }
+
+ boolean changed = false;
+
+ // Try to read configuration
+ Object o = properties.get(THREADPOOL_SIZE_PROPERTY);
+ if (o != null) {
+ // Convert value
+ Integer newSize = getIntegerProperty(o, DEFAULT_QUEUE_SIZE);
+
+ if (newSize != m_executorService.getMaximumPoolSize()) {
+ // Apply configuration change
+ m_executorService.setCorePoolSize(newSize);
+ m_executorService.setMaximumPoolSize(newSize);
+ m_properties.put(THREADPOOL_SIZE_PROPERTY, newSize);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ // Transfer unrecognized values in service properties as per spec. recommendation
+ for (Object key : Collections.list(properties.keys())) {
+ if (!THREADPOOL_SIZE_PROPERTY.equals(key)) {
+ m_properties.put(key.toString(), properties.get(key));
+ }
+ }
+
+ // Update registration object
+ getRegistration().setProperties(m_properties);
+ }
+
+ }
+
+ private Integer getIntegerProperty(final Object value, final Integer defaultValue) throws ConfigurationException {
+ Integer newSize = null;
+ if (value instanceof Integer) {
+ newSize = (Integer) value;
+ } else {
+ // Try to convert the value
+ try {
+ newSize = Integer.parseInt(value.toString());
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ return newSize;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactory.java
new file mode 100644
index 0000000..b1b5b5c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.extender.internal.queue;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * A thread factory that groups produced threads inside a given {@link java.lang.ThreadGroup}.
+ */
+public class GroupThreadFactory implements ThreadFactory {
+
+ /**
+ * Group for produced Threads.
+ */
+ private final ThreadGroup m_threadGroup;
+
+ public GroupThreadFactory() {
+ this(defaultThreadGroup());
+ }
+
+ /**
+ * Returns the default thread group just like {@link java.util.concurrent.Executors#defaultThreadFactory()}.
+ */
+ private static ThreadGroup defaultThreadGroup() {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null) {
+ return s.getThreadGroup();
+ } else {
+ return Thread.currentThread().getThreadGroup();
+ }
+ }
+
+ /**
+ * @param threadGroup group to be used for produced threads.
+ */
+ public GroupThreadFactory(final ThreadGroup threadGroup) {
+ m_threadGroup = threadGroup;
+ }
+
+ /**
+ * Creates a new thread.
+ * Prepend the prefix to the thread name
+ *
+ * @param r the runnable
+ * @return the thread object
+ */
+ public Thread newThread(Runnable r) {
+ return new Thread(m_threadGroup, r);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallable.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallable.java
new file mode 100644
index 0000000..2216533
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallable.java
@@ -0,0 +1,198 @@
+/*
+ * 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.extender.internal.queue;
+
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A callable computing job statistics. The job is given as another callable.
+ * The statistics are global, so must be used carefully.
+ */
+public class JobInfoCallable<T> implements Callable<T>, JobInfo {
+
+ /**
+ * Notifier helper for {@link org.apache.felix.ipojo.extender.queue.QueueListener}.
+ */
+ private final QueueNotifier m_queueNotifier;
+
+ /**
+ * The statistic object.
+ */
+ private final Statistic m_statistic;
+
+ /**
+ * The genuine job.
+ */
+ private final Job<T> m_delegate;
+
+ /**
+ * A callback notified when the job is processed.
+ */
+ private final Callback<T> m_callback;
+
+ /**
+ * The job description.
+ */
+ private final String m_description;
+
+ /**
+ * The date (in milli) when this object is created.
+ */
+ private long enlistmentTime = System.currentTimeMillis();
+
+ /**
+ * The date when the job processing started.
+ */
+ private long startTime = -1;
+
+ /**
+ * The date when the job processing is completed.
+ */
+ private long endTime = -1;
+
+ /**
+ * Creates the job info callable.
+ *
+ * @param queueNotifier notifier for QueueListeners
+ * @param statistic the statistics that will be populated
+ * @param delegate the real job
+ * @param callback the callback notified when the job is completed
+ * @param description the job description
+ */
+ public JobInfoCallable(QueueNotifier queueNotifier,
+ Statistic statistic,
+ Job<T> delegate,
+ Callback<T> callback,
+ String description) {
+ m_queueNotifier = queueNotifier;
+ m_statistic = statistic;
+ m_delegate = delegate;
+ m_callback = callback;
+ m_description = description;
+ m_statistic.getWaiters().add(this);
+
+ // Assume that we will be enlisted in the next few cycles
+ m_queueNotifier.fireEnlistedJobInfo(this);
+ }
+
+ /**
+ * Executes the job.
+ * This method updates the statistics.
+ *
+ * @return the job result
+ * @throws Exception the job execution failed
+ */
+ public T call() throws Exception {
+ m_statistic.getWaiters().remove(this);
+ startTime = System.currentTimeMillis();
+ m_statistic.getCurrentsCounter().incrementAndGet();
+ T result = null;
+ Exception exception = null;
+ try {
+ m_queueNotifier.fireStartedJobInfo(this);
+ result = m_delegate.call();
+ endTime = System.currentTimeMillis();
+ return result;
+ } catch (Exception e) {
+ endTime = System.currentTimeMillis();
+ m_queueNotifier.fireFailedJobInfo(this, e);
+ if (m_callback != null) {
+ m_callback.error(this, e);
+ }
+ exception = e;
+ throw e;
+ } finally {
+ m_statistic.getCurrentsCounter().decrementAndGet();
+ m_statistic.getFinishedCounter().incrementAndGet();
+
+ // Only exec success callbacks when no error occurred
+ if (exception == null) {
+ m_queueNotifier.fireExecutedJobInfo(this, result);
+ if (m_callback != null) {
+ m_callback.success(this, result);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the enlistment date.
+ */
+ public long getEnlistmentTime() {
+ return enlistmentTime;
+ }
+
+ /**
+ * @return the job start date.
+ */
+ public long getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * @return the job completion date.
+ */
+ public long getEndTime() {
+ return endTime;
+ }
+
+ /**
+ * Computes the time spent in the waiting queue
+ *
+ * @return the waited time, if the job is still waiting, gets the current waited time
+ */
+ public long getWaitDuration() {
+ long end = startTime;
+ if (end == -1) {
+ // Not yet started
+ // Still waiting
+ end = System.currentTimeMillis();
+ }
+ return end - enlistmentTime;
+ }
+
+ /**
+ * Computes the time spent to execute the job (this does not include the waiting).
+ * If the job is not executed yet, or is still executing, {@literal -1} is returned
+ *
+ * @return the execution duration, or {@literal -1}.
+ */
+ public long getExecutionDuration() {
+ if ((startTime == -1) || (endTime == -1)) {
+ return -1;
+ }
+ return endTime - startTime;
+ }
+
+ /**
+ * @return the job description
+ */
+ public String getDescription() {
+ return m_description;
+ }
+
+ public String getJobType() {
+ return m_delegate.getJobType();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactory.java
new file mode 100644
index 0000000..82f8540
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactory.java
@@ -0,0 +1,92 @@
+/*
+ * 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.extender.internal.queue;
+
+import static java.lang.String.format;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A thread factory setting the name of the created thread.
+ * This thread factory delegates the thread creation on another factory and format the name.
+ */
+public class NamingThreadFactory implements ThreadFactory {
+
+ /**
+ * Unique identifier generator.
+ */
+ private static final AtomicInteger IDENTIFIERS = new AtomicInteger(1);
+
+ /**
+ * Per-factory counter
+ */
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+ /**
+ * The wrapped thread factory on which creation is delegated.
+ */
+ private final ThreadFactory m_threadFactory;
+
+ /**
+ * Pool identifier.
+ */
+ private final int m_identifier;
+
+ /**
+ * For test only.
+ */
+ public static void reset() {
+ IDENTIFIERS.set(1);
+ }
+
+ /**
+ * Creates the object delegating to the given thread factory.
+ *
+ * @param threadFactory the thread factory
+ */
+ public NamingThreadFactory(ThreadFactory threadFactory) {
+ this(threadFactory, IDENTIFIERS.getAndIncrement());
+ }
+
+ /**
+ * Creates the object delegating to the given thread factory.
+ *
+ * @param threadFactory the thread factory
+ * @param identifier the pool identifier
+ */
+ private NamingThreadFactory(final ThreadFactory threadFactory, final int identifier) {
+ m_threadFactory = threadFactory;
+ m_identifier = identifier;
+ }
+
+ /**
+ * Creates a new thread.
+ * Format the Thread name
+ *
+ * @param r the runnable
+ * @return the thread object
+ */
+ public Thread newThread(Runnable r) {
+ Thread thread = m_threadFactory.newThread(r);
+ thread.setName(format("pool-%d-thread-%d", m_identifier, threadNumber.getAndIncrement()));
+ return thread;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactory.java
new file mode 100644
index 0000000..2c0dc46
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.extender.internal.queue;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * A thread factory setting the name of the created thread.
+ * This thread factory delegates the thread creation on another factory, it just set the thread name (actually just
+ * set a prefix).
+ */
+public class PrefixedThreadFactory implements ThreadFactory {
+
+ /**
+ * The wrapped thread factory on which creation is delegated.
+ */
+ private final ThreadFactory m_threadFactory;
+
+ /**
+ * The prefix.
+ */
+ private final String m_prefix;
+
+ /**
+ * Creates the object using the default thread factory.
+ *
+ * @param prefix the prefix
+ */
+ public PrefixedThreadFactory(String prefix) {
+ this(Executors.defaultThreadFactory(), prefix);
+ }
+
+ /**
+ * Creates the object delegating to the given thread factory.
+ *
+ * @param threadFactory the thread factory
+ * @param prefix the prefix
+ */
+ public PrefixedThreadFactory(ThreadFactory threadFactory, String prefix) {
+ m_threadFactory = threadFactory;
+ m_prefix = prefix;
+ }
+
+ /**
+ * Creates a new thread.
+ * Prepend the prefix to the thread name
+ *
+ * @param r the runnable
+ * @return the thread object
+ */
+ public Thread newThread(Runnable r) {
+ Thread thread = m_threadFactory.newThread(r);
+ thread.setName(m_prefix + thread.getName());
+ return thread;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/QueueNotifier.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/QueueNotifier.java
new file mode 100644
index 0000000..c7fdcfc
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/QueueNotifier.java
@@ -0,0 +1,32 @@
+/*
+ * 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.extender.internal.queue;
+
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+
+/**
+ * Internal interface to de-couple event producer and event listeners.
+ */
+public interface QueueNotifier {
+ void fireEnlistedJobInfo(JobInfo info);
+ void fireStartedJobInfo(JobInfo info);
+ void fireExecutedJobInfo(JobInfo info, Object result);
+ void fireFailedJobInfo(JobInfo info, Throwable throwable);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/Statistic.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/Statistic.java
new file mode 100644
index 0000000..52e232a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/Statistic.java
@@ -0,0 +1,70 @@
+/*
+ * 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.extender.internal.queue;
+
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Objects wrapping the {@link org.apache.felix.ipojo.extender.queue.QueueService} statistics.
+ */
+public class Statistic {
+ /**
+ * The synchronized list of waiting jobs.
+ */
+ private final List<JobInfo> m_waiters = Collections.synchronizedList(new ArrayList<JobInfo>());
+
+ /**
+ * The number of completed jobs.
+ */
+ private final AtomicInteger m_finished = new AtomicInteger(0);
+
+ /**
+ * The number of job being processed.
+ */
+ private final AtomicInteger m_currents = new AtomicInteger(0);
+
+ /**
+ * @return the number of completed jobs.
+ */
+ public AtomicInteger getFinishedCounter() {
+ return m_finished;
+ }
+
+ /**
+ * @return the list of waiting jobs.
+ */
+ public List<JobInfo> getWaiters() {
+ return m_waiters;
+ }
+
+ /**
+ * @return the number of jobs under processing.
+ */
+ public AtomicInteger getCurrentsCounter() {
+ return m_currents;
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueService.java
new file mode 100644
index 0000000..a9be788
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueService.java
@@ -0,0 +1,131 @@
+/*
+ * 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.extender.internal.queue;
+
+import org.apache.felix.ipojo.extender.internal.AbstractService;
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.BundleContext;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * An implementation of the Lifecycle Queue Service for synchronous processing.
+ */
+public class SynchronousQueueService extends AbstractQueueService implements LifecycleQueueService {
+
+ private final Statistic m_statistic = new Statistic();
+
+ public SynchronousQueueService(BundleContext bundleContext) {
+ super(bundleContext, QueueService.class);
+ }
+
+ @Override
+ protected Dictionary<String, ?> getServiceProperties() {
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+ properties.put(QueueService.QUEUE_MODE_PROPERTY, QueueService.SYNCHRONOUS_QUEUE_MODE);
+ return properties;
+ }
+
+ public int getFinished() {
+ return m_statistic.getFinishedCounter().get();
+ }
+
+ public int getWaiters() {
+ return 0;
+ }
+
+ public int getCurrents() {
+ return m_statistic.getCurrentsCounter().get();
+ }
+
+ public List<JobInfo> getWaitersInfo() {
+ return Collections.emptyList();
+ }
+
+ public <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description) {
+ JobInfoCallable<T> exec = new JobInfoCallable<T>(this, m_statistic, callable, callback, description);
+ try {
+ return new ImmediateFuture<T>(exec.call());
+ } catch (Exception e) {
+ return new ExceptionFuture<T>(e);
+ }
+
+ }
+
+ public <T> Future<T> submit(Job<T> callable, String description) {
+ return submit(callable, null, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable) {
+ return submit(callable, "No description");
+ }
+
+ private class ImmediateFuture<T> implements Future<T> {
+ private T m_result;
+
+ public ImmediateFuture(T result) {
+ m_result = result;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return true;
+ }
+
+ public T get() throws InterruptedException, ExecutionException {
+ return m_result;
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return get();
+ }
+ }
+
+ private class ExceptionFuture<T> extends ImmediateFuture<T> {
+ private ExecutionException m_exception;
+
+ public ExceptionFuture(Exception e) {
+ super(null);
+ m_exception = new ExecutionException(e);
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ throw m_exception;
+ }
+
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxy.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxy.java
new file mode 100644
index 0000000..0e040bb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxy.java
@@ -0,0 +1,157 @@
+/*
+ * 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.extender.internal.queue.debug;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+import org.apache.felix.ipojo.extender.queue.debug.QueueEventProxy;
+
+/**
+ * User: guillaume
+ * Date: 02/10/13
+ * Time: 10:51
+ */
+public class ReplayQueueEventProxy implements QueueEventProxy, QueueListener {
+ /**
+ * Store QueueListeners.
+ */
+ private final List<QueueListener> m_listeners = new ArrayList<QueueListener>();
+
+ /**
+ * Store QueueEvent to be replayed.
+ */
+ private List<QueueEvent> m_events = new CopyOnWriteArrayList<QueueEvent>();
+
+ public void addQueueListener(final QueueListener listener) {
+ m_listeners.add(listener);
+ // replay all the existing events to the new listener
+ replay(listener);
+ }
+
+ public void removeQueueListener(final QueueListener listener) {
+ m_listeners.remove(listener);
+ }
+
+ public void enlisted(final JobInfo info) {
+ EnlistedQueueEvent event = new EnlistedQueueEvent(info);
+ m_events.add(event);
+ forward(event);
+ }
+
+ public void started(final JobInfo info) {
+ StartedQueueEvent event = new StartedQueueEvent(info);
+ m_events.add(event);
+ forward(event);
+ }
+
+ public void executed(final JobInfo info, final Object result) {
+ ExecutedQueueEvent event = new ExecutedQueueEvent(info, result);
+ m_events.add(event);
+ forward(event);
+ }
+
+ public void failed(final JobInfo info, final Throwable throwable) {
+ FailedQueueEvent event = new FailedQueueEvent(info, throwable);
+ m_events.add(event);
+ forward(event);
+ }
+
+ /**
+ * Replay all stored events to the given QueueListener.
+ */
+ private void replay(final QueueListener listener) {
+ for (QueueEvent event : m_events) {
+ event.replay(listener);
+ }
+ }
+
+ /**
+ * Forward the given QueueEvent to all the registered listeners.
+ */
+ private void forward(final QueueEvent event) {
+ for (QueueListener listener : m_listeners) {
+ event.replay(listener);
+ }
+ }
+
+ /**
+ * Encapsulate event forwarding logic.
+ */
+ private interface QueueEvent {
+ void replay(QueueListener listener);
+ }
+
+ private class EnlistedQueueEvent implements QueueEvent {
+ private final JobInfo m_info;
+
+ public EnlistedQueueEvent(final JobInfo info) {
+ m_info = info;
+ }
+
+ public void replay(final QueueListener listener) {
+ listener.enlisted(m_info);
+ }
+ }
+
+ private class StartedQueueEvent implements QueueEvent {
+ private final JobInfo m_info;
+
+ public StartedQueueEvent(final JobInfo info) {
+ m_info = info;
+ }
+
+ public void replay(final QueueListener listener) {
+ listener.started(m_info);
+ }
+ }
+
+ private class ExecutedQueueEvent implements QueueEvent {
+ private final JobInfo m_info;
+ private final Object m_result;
+
+ public ExecutedQueueEvent(final JobInfo info, final Object result) {
+ m_info = info;
+ m_result = result;
+ }
+
+ public void replay(final QueueListener listener) {
+ listener.executed(m_info, m_result);
+ }
+ }
+
+ private class FailedQueueEvent implements QueueEvent {
+ private final JobInfo m_info;
+ private final Throwable m_throwable;
+
+ public FailedQueueEvent(final JobInfo info, final Throwable throwable) {
+ m_info = info;
+ m_throwable = throwable;
+ }
+
+ public void replay(final QueueListener listener) {
+ listener.failed(m_info, m_throwable);
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelection.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelection.java
new file mode 100644
index 0000000..c7cb3d7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelection.java
@@ -0,0 +1,55 @@
+/*
+ * 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.extender.internal.queue.pref;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A preference selection strategy based on a manifest header.
+ * By default, the {@literal IPOJO-Queue-Preference} header is used.
+ */
+public class HeaderPreferenceSelection implements PreferenceSelection {
+
+ private final String name;
+
+ public HeaderPreferenceSelection() {
+ this("IPOJO-Queue-Preference");
+ }
+
+ public HeaderPreferenceSelection(String name) {
+ this.name = name;
+ }
+
+ public Preference select(Bundle source) {
+ String header = source.getHeaders().get(name);
+
+ // No preference specified, return default
+ if (header == null) {
+ return Preference.DEFAULT;
+ }
+
+ header = header.trim();
+ try {
+ return Preference.valueOf(header.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ return Preference.DEFAULT;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/Preference.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/Preference.java
new file mode 100644
index 0000000..3a245f8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/Preference.java
@@ -0,0 +1,36 @@
+/*
+ * 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.extender.internal.queue.pref;
+
+/**
+ * The processing preference.
+ * <p/>
+ * Each bundle can set the desired processing strategy, however the system can override this choice.
+ * <p/>
+ * 3 strategies are possible:
+ * <ul>
+ * <li>SYNC: for synchronous processing</li>
+ * <li>ASYNC: for asynchronous processing</li>
+ * <li>DEFAULT: using the default behavior</li>
+ * </ul>
+ */
+public enum Preference {
+ SYNC, ASYNC, DEFAULT
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceQueueService.java
new file mode 100644
index 0000000..1316fe9
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceQueueService.java
@@ -0,0 +1,167 @@
+/*
+ * 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.extender.internal.queue.pref;
+
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleReference;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+/**
+ * An implementation of the queue service delegating on the synchronous and asynchronous implementations according to
+ * the processing preference.
+ */
+public class PreferenceQueueService implements LifecycleQueueService {
+
+ /**
+ * The preference selection strategy.
+ */
+ private final PreferenceSelection m_strategy;
+
+ /**
+ * The synchronous queue service.
+ */
+ private final LifecycleQueueService m_syncQueue;
+
+ /**
+ * The asynchronous queue service.
+ */
+ private final LifecycleQueueService m_asyncQueue;
+
+ /**
+ * The default queue service (chosen using the global preference).
+ */
+ private QueueService m_defaultQueue;
+
+ /**
+ * Creates the preference queue service.
+ *
+ * @param strategy the preference strategy
+ * @param syncQueue the synchronous queue service
+ * @param asyncQueue the asynchronous queue service
+ */
+ public PreferenceQueueService(PreferenceSelection strategy, LifecycleQueueService syncQueue, LifecycleQueueService asyncQueue) {
+ m_strategy = strategy;
+ m_syncQueue = syncQueue;
+ m_asyncQueue = asyncQueue;
+
+ // By default, system queue is asynchronous
+ m_defaultQueue = asyncQueue;
+ }
+
+ /**
+ * Starting queues.
+ */
+ public void start() {
+ m_syncQueue.start();
+ m_asyncQueue.start();
+ }
+
+ /**
+ * Stopping queues.
+ */
+ public void stop() {
+ m_syncQueue.stop();
+ m_asyncQueue.stop();
+ }
+
+ /**
+ * @return the number of completed jobs.
+ */
+ public int getFinished() {
+ return m_syncQueue.getFinished() + m_asyncQueue.getFinished();
+ }
+
+ /**
+ * @return the number of waiting jobs.
+ */
+ public int getWaiters() {
+ return m_syncQueue.getWaiters() + m_asyncQueue.getWaiters();
+ }
+
+ /**
+ * @return the number of jobs being processed.
+ */
+ public int getCurrents() {
+ return m_syncQueue.getCurrents() + m_asyncQueue.getCurrents();
+ }
+
+ /**
+ * Gets the number of waiting job. Notice that the synchronous queue does not have a waiting queue.
+ *
+ * @return the number of waiting job.
+ */
+ public List<JobInfo> getWaitersInfo() {
+ // synchronous queue as no waiters, so snapshot is always empty and can be ignored
+ return m_asyncQueue.getWaitersInfo();
+ }
+
+ /**
+ * Submits a job to the right queue.
+ * The queue selection works as follow:
+ * If the bundle submitting the queue has a preference, use this preference, otherwise use the default preference.
+ *
+ * @param callable the job
+ * @param callback callback called when the job is processed
+ * @param description a description of the job
+ * @return the reference of the submitted job
+ */
+ public <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description) {
+
+ Bundle bundle = callable.getBundle();
+ Preference preference = m_strategy.select(bundle);
+
+ QueueService selected = m_defaultQueue;
+ switch (preference) {
+ case ASYNC:
+ selected = m_asyncQueue;
+ break;
+ case SYNC:
+ selected = m_syncQueue;
+ break;
+ }
+
+ return selected.submit(callable, callback, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable, String description) {
+ return submit(callable, null, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable) {
+ return submit(callable, "No description");
+ }
+
+ public void addQueueListener(final QueueListener listener) {
+ // Intentionally blank, not intended to have listeners
+ }
+
+ public void removeQueueListener(final QueueListener listener) {
+ // Intentionally blank, not intended to have listeners
+ }
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceSelection.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceSelection.java
new file mode 100644
index 0000000..e07f451
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/PreferenceSelection.java
@@ -0,0 +1,29 @@
+/*
+ * 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.extender.internal.queue.pref;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * An interface to choose the processing preference.
+ */
+public interface PreferenceSelection {
+ Preference select(Bundle source);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueService.java
new file mode 100644
index 0000000..e0b0927
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueService.java
@@ -0,0 +1,131 @@
+/*
+ * 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.extender.internal.queue.pref.enforce;
+
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.internal.queue.pref.Preference;
+import org.apache.felix.ipojo.extender.internal.queue.pref.PreferenceSelection;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleReference;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+/**
+ * A queue service implementation enforcing the processing preference choice for the bundle.
+ */
+public class EnforcedQueueService extends ForwardingQueueService {
+
+ /**
+ * The preference strategy selection.
+ */
+ private final PreferenceSelection m_strategy;
+
+ /**
+ * The lifecycle queue service on which the job are delegated.
+ */
+ private final LifecycleQueueService m_queueService;
+
+ /**
+ * The preference.
+ */
+ private final Preference m_enforced;
+
+ /**
+ * The logger.
+ */
+ private final Log m_logger;
+
+ /**
+ * Constructor.
+ *
+ * @param strategy the strategy
+ * @param queueService the queue service
+ * @param enforced the preference we want to enforce
+ * @param logger the logger
+ */
+ public EnforcedQueueService(PreferenceSelection strategy, LifecycleQueueService queueService, Preference enforced, Log logger) {
+ m_strategy = strategy;
+ m_queueService = queueService;
+ m_enforced = enforced;
+ m_logger = logger;
+ }
+
+ @Override
+ protected LifecycleQueueService delegate() {
+ return m_queueService;
+ }
+
+ @Override
+ public <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description) {
+ checkBundlePreference(callable);
+ return super.submit(callable, callback, description);
+ }
+
+ @Override
+ public <T> Future<T> submit(Job<T> callable, String description) {
+ checkBundlePreference(callable);
+ return super.submit(callable, description);
+ }
+
+ @Override
+ public <T> Future<T> submit(Job<T> callable) {
+ checkBundlePreference(callable);
+ return super.submit(callable);
+ }
+
+ /**
+ * Checks the bundle processing preference and compare with the enforced preference.
+ *
+ * @param callable the callable
+ */
+ private void checkBundlePreference(Callable<?> callable) {
+ if (callable instanceof BundleReference) {
+ Bundle bundle = ((BundleReference) callable).getBundle();
+ Preference preference = m_strategy.select(bundle);
+
+ if (!isCompatible(preference)) {
+ // Log a warning, Bundle asked for a synchronous processing,
+ // but we will enforce parametrised processing
+ String message = String.format(
+ "Enforcing %s mode for Bundle %s/%s [%d] (asking for %s)",
+ m_enforced.name(),
+ bundle.getSymbolicName(),
+ bundle.getVersion(),
+ bundle.getBundleId(),
+ preference
+ );
+ m_logger.log(Logger.WARNING, message);
+ }
+ }
+ }
+
+ /**
+ * @param preference the preference.
+ * @return is the given preference compatible with the enforced one.
+ */
+ private boolean isCompatible(Preference preference) {
+ return ((preference == m_enforced) || (preference == Preference.DEFAULT));
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/ForwardingQueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/ForwardingQueueService.java
new file mode 100644
index 0000000..5c96728
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/ForwardingQueueService.java
@@ -0,0 +1,82 @@
+/*
+ * 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.extender.internal.queue.pref.enforce;
+
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+/**
+ * A queue service implementation delegating to a {@link LifecycleQueueService}.
+ */
+public abstract class ForwardingQueueService implements LifecycleQueueService {
+
+ protected abstract LifecycleQueueService delegate();
+
+ public void start() {
+ delegate().start();
+ }
+
+ public void stop() {
+ delegate().stop();
+ }
+
+ public int getFinished() {
+ return delegate().getFinished();
+ }
+
+ public int getWaiters() {
+ return delegate().getWaiters();
+ }
+
+ public int getCurrents() {
+ return delegate().getCurrents();
+ }
+
+ public List<JobInfo> getWaitersInfo() {
+ return delegate().getWaitersInfo();
+ }
+
+ public <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description) {
+ return delegate().submit(callable, callback, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable, String description) {
+ return delegate().submit(callable, description);
+ }
+
+ public <T> Future<T> submit(Job<T> callable) {
+ return delegate().submit(callable);
+ }
+
+ public void addQueueListener(final QueueListener listener) {
+ delegate().addQueueListener(listener);
+ }
+
+ public void removeQueueListener(final QueueListener listener) {
+ delegate().removeQueueListener(listener);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Callback.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Callback.java
new file mode 100644
index 0000000..5a8dded
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Callback.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.extender.queue;
+
+/**
+ * When submitting a processing job, a callback object can be passed to the submission process. This callback is
+ * notified when the job processing is completed.
+ */
+public interface Callback<T> {
+ /**
+ * The job was completed successfully.
+ *
+ * @param info the job info
+ * @param result the job result
+ */
+ void success(JobInfo info, T result);
+
+ /**
+ * The job was not completed successfully.
+ *
+ * @param info the job info
+ * @param exception the thrown exception
+ */
+ void error(JobInfo info, Exception exception);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Job.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Job.java
new file mode 100644
index 0000000..0451cfb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/Job.java
@@ -0,0 +1,36 @@
+/*
+ * 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.extender.queue;
+
+import java.util.concurrent.Callable;
+
+import org.osgi.framework.BundleReference;
+
+/**
+ * Represents a task that can be executed by the {@link org.apache.felix.ipojo.extender.queue.QueueService}.
+ */
+public interface Job<T> extends Callable<T>, BundleReference {
+
+ /**
+ * The {@code jobType} is used to describe what is this job about.
+ * @return the job type identifier
+ */
+ String getJobType();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/JobInfo.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/JobInfo.java
new file mode 100644
index 0000000..0c359f5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/JobInfo.java
@@ -0,0 +1,74 @@
+/*
+ * 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.extender.queue;
+
+/**
+ * Interface to retrieve information about the job execution.
+ */
+public interface JobInfo {
+
+ /**
+ * Gets the submission time of the job.
+ *
+ * @return the submission time
+ */
+ long getEnlistmentTime();
+
+ /**
+ * Gets the starting time. This is the date when the job execution starts.
+ *
+ * @return the start time
+ */
+ long getStartTime();
+
+ /**
+ * Gets the completion time. This is the date when the job execution ends.
+ *
+ * @return the end time
+ */
+ long getEndTime();
+
+ /**
+ * Gets the time spent in the waiting queue.
+ *
+ * @return the waited time
+ */
+ long getWaitDuration();
+
+ /**
+ * Gets the execution duration.
+ *
+ * @return the execution duration, {@literal -1} if this duration cannot be computed
+ */
+ long getExecutionDuration();
+
+ /**
+ * Gets the job description
+ *
+ * @return the description
+ */
+ String getDescription();
+
+ /**
+ * Gets the job's type identifier. May be {@code null} if not provided.
+ * @return job type identifier
+ */
+ String getJobType();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueListener.java
new file mode 100644
index 0000000..5518aa5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueListener.java
@@ -0,0 +1,67 @@
+/*
+ * 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.extender.queue;
+
+/**
+ * A {@link org.apache.felix.ipojo.extender.queue.QueueListener} provides queue management information to external entities:
+ * <ul>
+ * <li>Job submission</li>
+ * <li>Job execution</li>
+ * <li>Job result (success or failure)</li>
+ * </ul>
+ *
+ * Implementer of this interface should not block as the invocation is done synchronously.
+ * Implementers are responsible to register themselves in the {@link org.apache.felix.ipojo.extender.queue.QueueService} they'll observe.
+ */
+public interface QueueListener {
+
+ /**
+ * Invoked when a job is just being enlisted (before processing).
+ * Only {@link JobInfo#getEnlistmentTime()} and {@link JobInfo#getWaitDuration()} provides meaningful values.
+ * Note that {@code waitDuration} value is re-evaluated at each call.
+ * @param info The job being enlisted
+ */
+ void enlisted(JobInfo info);
+
+ /**
+ * Invoked when a job's execution is just about to be started.
+ * Only {@link JobInfo#getEnlistmentTime()}, {@link JobInfo#getWaitDuration()}, {@link JobInfo#getStartTime()}
+ * and {@link JobInfo#getExecutionDuration()} provides meaningful values.
+ * Note that {@code executionDuration} value is re-evaluated at each call.
+ * @param info The job being started
+ */
+ void started(JobInfo info);
+
+ /**
+ * Invoked when a job's execution is finished successfully.
+ * Note the implementers should not retain any references to the provided {@code result} (memory leak).
+ * @param info The executed job
+ * @param result The job's result
+ */
+ void executed(JobInfo info, Object result);
+
+ /**
+ * Invoked when a job's execution is finished with error.
+ * Note the implementers should not retain any references to the provided {@code throwable} (memory leak).
+ * @param info The failed job
+ * @param throwable The job's thrown exception
+ */
+ void failed(JobInfo info, Throwable throwable);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueService.java
new file mode 100644
index 0000000..00f808a
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/QueueService.java
@@ -0,0 +1,125 @@
+/*
+ * 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.extender.queue;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+/**
+ * Definition of the queue service.
+ * The queue service is used to enqueue the bundle processing job.
+ * The processing order is depending of the implementation.
+ */
+public interface QueueService {
+ /**
+ * The service property specifying the queue mode (sync/async/pref).
+ */
+ String QUEUE_MODE_PROPERTY = "ipojo.queue.mode";
+
+ /**
+ * Synchronous queue mode.
+ */
+ String SYNCHRONOUS_QUEUE_MODE = "sync";
+
+ /**
+ * Asynchronous queue mode.
+ */
+ String ASYNCHRONOUS_QUEUE_MODE = "async";
+
+ /**
+ * Preference queue mode.
+ */
+ String PREFERENCE_QUEUE_MODE = "pref";
+
+ /**
+ * The service property specifying the queue scope (global/...).
+ */
+ String QUEUE_SCOPE_PROPERTY = "ipojo.queue.scope";
+
+ /**
+ * Global queue scope.
+ */
+ String GLOABL_QUEUE_SCOPE = "global";
+
+ /**
+ * @return the number of jobs that have been executed entirely
+ * (including successful and erroneous jobs).
+ */
+ int getFinished();
+
+ /**
+ * @return the number of jobs scheduled but not yet started.
+ */
+ int getWaiters();
+
+ /**
+ * @return the number of jobs currently executed (started but not finished).
+ */
+ int getCurrents();
+
+ /**
+ * @return a snapshot of the currently waiting jobs.
+ */
+ List<JobInfo> getWaitersInfo();
+
+ // Note: I don't want us to store error reports there
+ // Maybe we should use EventAdmin to send notifications ?
+ // getErrors
+
+ /**
+ * Submits a job to the queue service.
+ *
+ * @param callable the job
+ * @param callback callback called when the job is processed
+ * @param description a description of the job
+ * @return the future object to retrieve the result
+ */
+ <T> Future<T> submit(Job<T> callable, Callback<T> callback, String description);
+
+ /**
+ * Submits a job to the queue service.
+ *
+ * @param callable the job
+ * @param description a description of the job
+ * @return the future object to retrieve the result
+ */
+ <T> Future<T> submit(Job<T> callable, String description);
+
+ /**
+ * Submits a job to the queue service.
+ *
+ * @param callable the job
+ * @return the future object to retrieve the result
+ */
+ <T> Future<T> submit(Job<T> callable);
+
+ /**
+ * Add a {@link QueueListener} that will be notified on events relative to this {@link QueueService}.
+ * @param listener added listener
+ */
+ void addQueueListener(QueueListener listener);
+
+ /**
+ * Remove a {@link QueueListener} from this {@link QueueService}.
+ * @param listener removed listener
+ */
+ void removeQueueListener(QueueListener listener);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/debug/QueueEventProxy.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/debug/QueueEventProxy.java
new file mode 100644
index 0000000..16dce7d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/queue/debug/QueueEventProxy.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.extender.queue.debug;
+
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+
+/**
+ * This service record events from a {@link org.apache.felix.ipojo.extender.queue.QueueService}.
+ * When a listener is added, all recorded events are replayed into the listener.
+ */
+public interface QueueEventProxy {
+ /**
+ * Add a {@link org.apache.felix.ipojo.extender.queue.QueueListener} that will be notified on events
+ * relative to the observed {@link org.apache.felix.ipojo.extender.queue.QueueService}.
+ * @param listener added listener
+ */
+ void addQueueListener(QueueListener listener);
+
+ /**
+ * Remove a {@link QueueListener} from the observed {@link org.apache.felix.ipojo.extender.queue.QueueService}.
+ * @param listener removed listener
+ */
+ void removeQueueListener(QueueListener listener);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
new file mode 100644
index 0000000..4078b87
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
@@ -0,0 +1,116 @@
+/*
+ * 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.handlers.architecture;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.InstanceStateListener;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.SecurityHelper;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+/**
+ * Architecture Handler. Provide a runtime representation of iPOJO instances.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ArchitectureHandler extends PrimitiveHandler implements Architecture, InstanceStateListener {
+
+ /**
+ * Name of the component.
+ */
+ private String m_name;
+ /**
+ * The Architecture service registration.
+ */
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ * Configure the handler.
+ *
+ * @param metadata : the metadata of the component
+ * @param configuration : the instance configuration
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) {
+ m_name = (String) configuration.get(Factory.INSTANCE_NAME_PROPERTY);
+ Dictionary<String, String> dict = new Hashtable<String, String>();
+ dict.put(ARCHITECTURE_INSTANCE, m_name);
+
+ if (SecurityHelper.canRegisterService(getInstanceManager().getContext())) {
+ debug("Registering architecture service for " + m_name);
+ m_serviceRegistration = getInstanceManager().getContext().registerService(Architecture.class.getName(), this, dict);
+ // We can't use the regular handler stateChanged method as this method is not called when the instance is
+ // disposed. This handler stays actives until the instance disposal.
+ getInstanceManager().addInstanceStateListener(this);
+ } else {
+ error("Cannot register the architecture service, bundle " + getInstanceManager().getContext().getBundle()
+ .getBundleId() + " is not in a valid state" );
+ }
+ }
+
+ /**
+ * Stop method.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ // Nothing do do when stopping.
+ }
+
+ /**
+ * Start method.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Nothing to do.
+ }
+
+ /**
+ * Get the instance description.
+ *
+ * @return the instance description
+ * @see org.apache.felix.ipojo.architecture.Architecture#getInstanceDescription()
+ */
+ public InstanceDescription getInstanceDescription() {
+ return getInstanceManager().getInstanceDescription();
+ }
+
+ /**
+ * The instance lifecycle listener callback.
+ * When we receive the DISPOSED state, the architecture is unregistered from the service registry.
+ *
+ * @param instance the changing instance the instance, meaningless in our case.
+ * @param newState the new instance state the new instance state.
+ */
+ public void stateChanged(ComponentInstance instance, int newState) {
+ if (newState == ComponentInstance.DISPOSED && m_serviceRegistration != null) {
+ debug("Withdrawing the architecture service of " + m_name + " due to instance disposal");
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+ }
+ }
+}
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
new file mode 100644
index 0000000..e5da154
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
@@ -0,0 +1,909 @@
+/*
+ * 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.handlers.configuration;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Log;
+import org.apache.felix.ipojo.util.Property;
+import org.apache.felix.ipojo.util.SecurityHelper;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+
+import java.util.*;
+
+/**
+ * Handler managing the Configuration Admin.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConfigurationHandler extends PrimitiveHandler implements ManagedService {
+
+ public static final String MANAGED_SERVICE_PID = "managed.service.pid";
+ /**
+ * List of the configurable fields.
+ */
+ private List<Property> m_configurableProperties = new ArrayList<Property>(1);
+ /**
+ * ProvidedServiceHandler of the component. It is useful to propagate
+ * properties to service registrations.
+ */
+ private ProvidedServiceHandler m_providedServiceHandler;
+ /**
+ * Properties propagated during the last instance "update".
+ */
+ private Dictionary m_propagatedFromInstance = new Properties();
+ /**
+ * Properties to propagate.
+ */
+ private Dictionary<String, Object> m_toPropagate = new Hashtable<String, Object>();
+ /**
+ * Properties propagated from the configuration admin.
+ */
+ private Dictionary m_propagatedFromCA;
+ /**
+ * Check if the instance was already reconfigured by the configuration admin.
+ */
+ private boolean m_configurationAlreadyPushed;
+ /**
+ * should the component propagate configuration ?
+ */
+ private boolean m_mustPropagate;
+ /**
+ * Service Registration to publish the service registration.
+ */
+ private ServiceRegistration m_sr;
+ /**
+ * Managed Service PID.
+ * This PID must be different from the instance name if the instance was created
+ * with the Configuration Admin.
+ */
+ private String m_managedServicePID;
+ /**
+ * the handler description.
+ */
+ private ConfigurationHandlerDescription m_description;
+ /**
+ * Updated method.
+ * This method is called when a reconfiguration is completed.
+ */
+ private Callback m_updated;
+ /**
+ * The configuration listeners.
+ */
+ private final Set<ConfigurationListener> m_listeners = new LinkedHashSet<ConfigurationListener>();
+ /**
+ * The last configuration sent to listeners.
+ */
+ private Map<String, Object> m_lastConfiguration;
+
+ /**
+ * Initialize the component type.
+ *
+ * @param desc : component type description to populate.
+ * @param metadata : component type metadata.
+ * @throws ConfigurationException : metadata are incorrect.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription desc, Element metadata) throws ConfigurationException {
+ Element[] confs = metadata.getElements("Properties", "");
+ if (confs == null) {
+ return;
+ }
+ Element[] configurables = confs[0].getElements("Property");
+ for (int i = 0; configurables != null && i < configurables.length; i++) {
+ String fieldName = configurables[i].getAttribute("field");
+ String methodName = configurables[i].getAttribute("method");
+ String paramIndex = configurables[i].getAttribute("constructor-parameter");
+
+ if (fieldName == null && methodName == null && paramIndex == null) {
+ throw new ConfigurationException("Malformed property : The property needs to contain" +
+ " at least a field, a method or a constructor-parameter");
+ }
+
+ String name = configurables[i].getAttribute("name");
+ if (name == null) {
+ if (fieldName == null && methodName != null) {
+ name = methodName;
+ } else if (fieldName == null && paramIndex != null) {
+ // Extract the name from the arguments.
+ MethodMetadata[] constructors = getFactory().getPojoMetadata().getConstructors();
+ if (constructors.length != 1) {
+ throw new ConfigurationException("Cannot infer the property name injected in the constructor " +
+ "parameter #" + paramIndex + " - add the `name` attribute");
+ } else {
+ int idx = Integer.valueOf(paramIndex);
+ if (constructors[0].getMethodArgumentNames().length > idx) {
+ name = constructors[0].getMethodArgumentNames()[idx];
+ } else {
+ throw new ConfigurationException("Cannot infer the property name injected in the constructor " +
+ "parameter #" + paramIndex + " - not enough argument in the constructor :" +
+ constructors[0].getArguments());
+ }
+ }
+ } else {
+ name = fieldName;
+ }
+ configurables[i].addAttribute(new Attribute("name", name)); // Add the type to avoid configure checking
+ }
+
+ String value = configurables[i].getAttribute("value");
+
+ // Detect the type of the property
+ PojoMetadata manipulation = getFactory().getPojoMetadata();
+ String type = null;
+ if (methodName != null) {
+ MethodMetadata[] method = manipulation.getMethods(methodName);
+ if (method.length == 0) {
+ type = configurables[i].getAttribute("type");
+ if (type == null) {
+ throw new ConfigurationException("Malformed property : The type of the property cannot be discovered, add a 'type' attribute");
+ }
+ } else {
+ if (method[0].getMethodArguments().length != 1) {
+ throw new ConfigurationException("Malformed property : The method " + methodName + " does not have one argument");
+ }
+ type = method[0].getMethodArguments()[0];
+ configurables[i].addAttribute(new Attribute("type", type)); // Add the type to avoid configure checking
+ }
+ } else if (fieldName != null) {
+ FieldMetadata field = manipulation.getField(fieldName);
+ if (field == null) {
+ throw new ConfigurationException("Malformed property : The field " + fieldName + " does not exist in the implementation class");
+ }
+ type = field.getFieldType();
+ configurables[i].addAttribute(new Attribute("type", type)); // Add the type to avoid configure checking
+ } else if (paramIndex != null) {
+ int index = Integer.parseInt(paramIndex);
+ type = configurables[i].getAttribute("type");
+ MethodMetadata[] cts = manipulation.getConstructors();
+ // If we don't have a type, try to get the first constructor and get the type of the parameter
+ // we the index 'index'.
+ if (type == null && cts.length > 0 && cts[0].getMethodArguments().length > index) {
+ type = cts[0].getMethodArguments()[index];
+ } else if (type == null) { // Applied only if type was not determined.
+ throw new ConfigurationException("Cannot determine the type of the property " + index +
+ ", please use the type attribute");
+ }
+ configurables[i].addAttribute(new Attribute("type", type));
+ }
+
+ // Is the property set to immutable
+ boolean immutable = false;
+ String imm = configurables[i].getAttribute("immutable");
+ immutable = imm != null && imm.equalsIgnoreCase("true");
+
+ boolean mandatory = false;
+ String man = configurables[i].getAttribute("mandatory");
+ mandatory = man != null && man.equalsIgnoreCase("true");
+
+ PropertyDescription pd;
+ if (value == null) {
+ pd = new PropertyDescription(name, type, null, false); // Cannot be immutable if we have no value.
+ } else {
+ pd = new PropertyDescription(name, type, value, immutable);
+ }
+
+ if (mandatory) {
+ pd.setMandatory();
+ }
+
+ desc.addProperty(pd);
+ }
+
+ }
+
+ /**
+ * Configures the handler.
+ * Access to field does not require synchronization as this method is executed
+ * before any thread access to this object.
+ *
+ * @param metadata the metadata of the component
+ * @param configuration the instance configuration
+ * @throws ConfigurationException one property metadata is not correct
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ // Build the map
+ Element[] confs = metadata.getElements("Properties", "");
+ Element[] configurables = confs[0].getElements("Property");
+
+ // Check if the component is dynamically configurable
+ // Propagation enabled by default.
+ m_mustPropagate = true;
+ // We must create a copy as the Config Admin dictionary has some limitations
+ m_toPropagate = new Hashtable<String, Object>();
+ if (configuration != null) {
+ Enumeration keys = configuration.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ // To conform with 'Property Propagation 104.4.4 (Config Admin spec)',
+ // we don't propagate properties starting with .
+ if (!excluded(key)) {
+ m_toPropagate.put(key, configuration.get(key));
+ }
+ }
+ }
+
+ String propa = confs[0].getAttribute("propagation");
+ if (propa != null && propa.equalsIgnoreCase("false")) {
+ m_mustPropagate = false;
+ m_toPropagate = null;
+ }
+
+ // Check if the component support ConfigurationADmin reconfiguration
+ m_managedServicePID = confs[0].getAttribute("pid"); // Look inside the component type description
+ String instanceMSPID = (String) configuration.get(MANAGED_SERVICE_PID); // Look inside the instance configuration.
+ if (instanceMSPID != null) {
+ m_managedServicePID = instanceMSPID;
+ }
+
+ // updated method
+ String upd = confs[0].getAttribute("updated");
+ if (upd != null) {
+ MethodMetadata method = getPojoMetadata().getMethod(upd);
+ if (method == null) {
+ throw new ConfigurationException("The updated method is not found in the class "
+ + getInstanceManager().getClassName());
+ } else if (method.getMethodArguments().length == 0) {
+ m_updated = new Callback(upd, new Class[0], false, getInstanceManager());
+ } else if (method.getMethodArguments().length == 1
+ && method.getMethodArguments()[0].equals(Dictionary.class.getName())) {
+ m_updated = new Callback(upd, new Class[]{Dictionary.class}, false, getInstanceManager());
+ } else {
+ throw new ConfigurationException("The updated method is found in the class "
+ + getInstanceManager().getClassName() + " must have either no argument or a Dictionary");
+ }
+ }
+
+ for (int i = 0; configurables != null && i < configurables.length; i++) {
+ String fieldName = configurables[i].getAttribute("field");
+ String methodName = configurables[i].getAttribute("method");
+ String paramIndex = configurables[i].getAttribute("constructor-parameter");
+ int index = -1;
+
+ String name = configurables[i].getAttribute("name"); // The initialize method has fixed the property name.
+ String value = configurables[i].getAttribute("value");
+
+ String type = configurables[i].getAttribute("type"); // The initialize method has fixed the property name.
+
+ Property prop;
+ if (paramIndex == null) {
+ prop = new Property(name, fieldName, methodName, value, type, getInstanceManager(), this);
+ } else {
+ index = Integer.parseInt(paramIndex);
+ prop = new Property(name, fieldName, methodName, index,
+ value, type, getInstanceManager(), this);
+ }
+ addProperty(prop);
+
+ // Check if the instance configuration contains value for the current property :
+ if (configuration.get(name) == null) {
+ if (fieldName != null && configuration.get(fieldName) != null) {
+ prop.setValue(configuration.get(fieldName));
+ }
+ } else {
+ prop.setValue(configuration.get(name));
+ }
+
+ if (fieldName != null) {
+ FieldMetadata field = new FieldMetadata(fieldName, type);
+ getInstanceManager().register(field, prop);
+ }
+
+ if (index != -1) {
+ getInstanceManager().register(index, prop);
+ }
+ }
+
+ m_description = new ConfigurationHandlerDescription(this, m_configurableProperties, m_managedServicePID);
+
+ }
+
+ /**
+ * Stop method.
+ * This method is synchronized to avoid the configuration admin pushing a configuration during the un-registration.
+ * Do nothing.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public synchronized void stop() {
+ if (m_sr != null) {
+ m_sr.unregister();
+ m_sr = null;
+ }
+ m_lastConfiguration = Collections.emptyMap();
+ }
+
+ /**
+ * Start method.
+ * This method is synchronized to avoid the config admin pushing a configuration before ending the method.
+ * Propagate properties if the propagation is activated.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public synchronized void start() {
+ // Get the provided service handler :
+ m_providedServiceHandler = (ProvidedServiceHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":provides");
+
+
+ // Propagation
+ if (m_mustPropagate) {
+ for (Property prop : m_configurableProperties) {
+ if (prop.getValue() != Property.NO_VALUE && prop.getValue() != null) { // No injected value, or null
+ m_toPropagate.put(prop.getName(), prop.getValue());
+ }
+ }
+
+ // 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);
+ }
+ }
+ }
+
+
+ // Give initial values and reset the 'invoked' flag.
+ for (Property prop : m_configurableProperties) {
+ prop.reset(); // Clear the invoked flag.
+ if (prop.hasField() && prop.getValue() != Property.NO_VALUE && prop.getValue() != null) {
+ getInstanceManager().onSet(null, prop.getField(), prop.getValue());
+ }
+ }
+
+ if (m_managedServicePID != null && m_sr == null) {
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_PID, m_managedServicePID);
+ props.put(Factory.INSTANCE_NAME_PROPERTY, getInstanceManager().getInstanceName());
+ props.put("factory.name", getInstanceManager().getFactory().getFactoryName());
+
+ // Security Check
+ if (SecurityHelper.hasPermissionToRegisterService(ManagedService.class.getName(),
+ getInstanceManager().getContext()) && SecurityHelper.canRegisterService
+ (getInstanceManager().getContext())) {
+ m_sr = getInstanceManager().getContext().registerService(ManagedService.class.getName(), this, props);
+ } else {
+ error("Cannot register the ManagedService - The bundle "
+ + getInstanceManager().getContext().getBundle().getBundleId()
+ + " does not have the permission to register the service");
+ }
+ }
+ }
+
+ /**
+ * Adds the given property metadata to the property metadata list.
+ *
+ * @param prop : property metadata to add
+ */
+ protected void addProperty(Property prop) {
+ m_configurableProperties.add(prop);
+ }
+
+ /**
+ * Reconfigure the component instance.
+ * Check if the new configuration modifies the current configuration.
+ * Invokes the updated method if needed.
+ *
+ * @param configuration : the new configuration
+ * @see org.apache.felix.ipojo.Handler#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary configuration) {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ boolean changed = false;
+ synchronized (this) {
+ info(getInstanceManager().getInstanceName() + " is reconfiguring the properties : " + configuration);
+
+ // Is there any changes ?
+ changed = detectConfigurationChanges(configuration);
+ if (changed) {
+ Properties extra = reconfigureProperties(configuration);
+ 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);
+ }
+ }
+ // Make a snapshot of the current configuration
+ for (Property p : m_configurableProperties) {
+ map.put(p.getName(), p.getValue());
+ }
+ }
+ }
+
+ if (changed) {
+ notifyListeners(map);
+ }
+ }
+
+ private boolean detectConfigurationChanges(Dictionary configuration) {
+ Enumeration keysEnumeration = configuration.keys();
+ while (keysEnumeration.hasMoreElements()) {
+ String name = (String) keysEnumeration.nextElement();
+ Object value = configuration.get(name);
+
+ // Some properties are skipped
+ if (name.equals(Factory.INSTANCE_NAME_PROPERTY)
+ || name.equals(Constants.SERVICE_PID)
+ || name.equals(MANAGED_SERVICE_PID)) {
+ continue;
+ }
+ // Do we have a property.
+ Property p = getPropertyByName(name);
+ if (p != null) {
+ // Change detection based on the value.
+ if (p.getValue() == null) {
+ return true;
+ } else if (! p.getValue().equals(value)) {
+ return true;
+ }
+ } else {
+ // Was it propagated ?
+ if (m_propagatedFromCA != null) {
+ Object v = m_propagatedFromCA.get(name);
+ if (v == null || ! v.equals(value)) {
+ return true;
+ }
+ }
+ if (m_propagatedFromInstance != null) {
+ Object v = m_propagatedFromInstance.get(name);
+ if (v == null || ! v.equals(value)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ // A propagated property may have been removed.
+ if (m_propagatedFromCA != null) {
+ Enumeration enumeration = m_propagatedFromCA.keys();
+ while (enumeration.hasMoreElements()) {
+ String k = (String) enumeration.nextElement();
+ if (configuration.get(k) == null) {
+ return true;
+ }
+ }
+ }
+ if (m_propagatedFromInstance != null) {
+ Enumeration enumeration = m_propagatedFromInstance.keys();
+ while (enumeration.hasMoreElements()) {
+ String k = (String) enumeration.nextElement();
+ if (configuration.get(k) == null) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Property getPropertyByName(String name) {
+ for (Property p : m_configurableProperties) {
+ if (p.getName().equals(name)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Reconfigured configuration properties and returns non matching properties.
+ * When called, it must hold the monitor lock.
+ *
+ * @param configuration : new configuration
+ * @return the properties that does not match with configuration properties
+ */
+ private Properties reconfigureProperties(Dictionary configuration) {
+ Properties toPropagate = new Properties();
+ Enumeration keysEnumeration = configuration.keys();
+ while (keysEnumeration.hasMoreElements()) {
+ String name = (String) keysEnumeration.nextElement();
+ Object value = configuration.get(name);
+ boolean found = false;
+ // Check if the name is a configurable property
+ for (Property prop : m_configurableProperties) {
+ if (prop.getName().equals(name)) {
+ Object v = reconfigureProperty(prop, value);
+ found = true;
+ if (m_mustPropagate && ! excluded(name)) {
+ toPropagate.put(name, v);
+ }
+ break; // Exit the search loop
+ }
+ }
+
+ if (!found && m_mustPropagate && ! excluded(name)) {
+ toPropagate.put(name, value);
+ }
+ }
+
+ // Every removed configurable property gets reset to its default value
+ for (Property prop : m_configurableProperties) {
+ if (configuration.get(prop.getName()) == null) {
+ reconfigureProperty(prop, prop.getDefaultValue());
+ }
+ }
+ return toPropagate;
+
+ }
+
+ /**
+ * Checks whether the property with this given name must not be propagated.
+ * @param name the name of the property
+ * @return {@code true} if the property must not be propagated
+ */
+ private boolean excluded(String name) {
+ return name.startsWith(".")
+ || Factory.INSTANCE_NAME_PROPERTY.equals(name)
+ || Factory.FACTORY_VERSION_PROPERTY.equals(name)
+ || "factory.name".equals(name);
+ }
+
+ /**
+ * Reconfigures the given property with the given value.
+ * This methods handles {@link org.apache.felix.ipojo.InstanceManager#onSet(Object, String, Object)}
+ * call and the callback invocation.
+ * The reconfiguration occurs only if the value changes.
+ *
+ * @param prop the property object to reconfigure
+ * @param value the new value.
+ * @return the new property value
+ */
+ public Object reconfigureProperty(Property prop, Object value) {
+ if (prop.getValue() == null || !prop.getValue().equals(value)) {
+ prop.setValue(value);
+ if (prop.hasField()) {
+ getInstanceManager().onSet(null, prop.getField(), prop.getValue()); // Notify other handler of the field value change.
+ }
+ if (prop.hasMethod()) {
+ if (getInstanceManager().getPojoObjects() != null) {
+ prop.invoke(null); // Call on all created pojo objects.
+ }
+ }
+ }
+ return prop.getValue();
+ }
+
+ /**
+ * Removes the old properties from the provided services and propagate new properties.
+ *
+ * @param newProps : new properties to propagate
+ * @param oldProps : old properties to remove
+ */
+ private void propagate(Dictionary newProps, Dictionary oldProps) {
+ if (m_mustPropagate && m_providedServiceHandler != null) {
+ if (oldProps != null) {
+ m_providedServiceHandler.removeProperties(oldProps);
+ }
+
+ if (newProps != null) {
+ // Remove the name, the pid and the managed service pid props
+ newProps.remove(Factory.INSTANCE_NAME_PROPERTY);
+ newProps.remove(MANAGED_SERVICE_PID);
+ newProps.remove(Constants.SERVICE_PID);
+
+ // Remove all properties starting with . (config admin specification)
+ Enumeration<String> keys = newProps.keys();
+ List<String> propertiesStartingWithDot = new ArrayList<String>();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ if (key.startsWith(".")) {
+ propertiesStartingWithDot.add(key);
+ }
+ }
+ for (String k : propertiesStartingWithDot) {
+ newProps.remove(k);
+ }
+
+ // Propagation of the properties to service registrations :
+ m_providedServiceHandler.addProperties(newProps);
+ }
+ }
+ }
+
+ /**
+ * Handler createInstance method.
+ * This method is override to allow delayed callback invocation.
+ * Invokes the updated method if needed.
+ *
+ * @param instance : the created object
+ * @see org.apache.felix.ipojo.PrimitiveHandler#onCreation(Object)
+ */
+ public void onCreation(Object instance) {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ for (Property prop : m_configurableProperties) {
+ if (prop.hasMethod()) {
+ prop.invoke(instance);
+ }
+ // Fill the snapshot copy while calling callbacks
+ map.put(prop.getName(), prop.getValue());
+ }
+
+ try {
+ notifyUpdated(instance);
+ } catch (Throwable e) {
+ error("Cannot call the updated method : " + e.getMessage(), e);
+ }
+ notifyListeners(map);
+ }
+
+ /**
+ * Invokes the updated method.
+ * This method build the dictionary containing all valued properties,
+ * as well as properties propagated to the provided service handler (
+ * only if the propagation is enabled).
+ *
+ * @param instance the instance on which the callback must be called.
+ * If <code>null</code> the callback is called on all the existing
+ * object.
+ */
+ private void notifyUpdated(Object instance) {
+ if (m_updated == null) {
+ return;
+ }
+
+ if (m_updated.getArguments().length == 0) {
+ // We don't have to compute the properties,
+ // we just call the callback.
+ try {
+ if (instance == null) {
+ m_updated.call(new Object[0]);
+ } else {
+ m_updated.call(instance, new Object[0]);
+ }
+ } catch (Exception e) {
+ error("Cannot call the updated method " + m_updated.getMethod() + " : " + e.getMessage());
+ }
+ return;
+ }
+
+ // Else we must compute the properties.
+ Properties props = new Properties();
+ for (Property property : m_configurableProperties) {
+ String n = property.getName();
+ Object v = property.getValue();
+ if (v != Property.NO_VALUE) {
+ props.put(n, v);
+ }
+ }
+ // add propagated properties to the list if propagation is enabled
+ if (m_mustPropagate) {
+ // Start by properties from the configuration admin,
+ if (m_propagatedFromCA != null) {
+
+ Enumeration e = m_propagatedFromCA.keys();
+ while (e.hasMoreElements()) {
+ String k = (String) e.nextElement();
+ if (!k.equals(Factory.INSTANCE_NAME_PROPERTY)) {
+ props.put(k, m_propagatedFromCA.get(k));
+ }
+ }
+ }
+ // Do also the one from the instance configuration
+ if (m_propagatedFromInstance != null) {
+ Enumeration e = m_propagatedFromInstance.keys();
+ while (e.hasMoreElements()) {
+ String k = (String) e.nextElement();
+ if (!k.equals(Factory.INSTANCE_NAME_PROPERTY)) { // Skip instance.name
+ props.put(k, m_propagatedFromInstance.get(k));
+ }
+ }
+ }
+ }
+
+ try {
+ if (instance == null) {
+ m_updated.call(new Object[]{props});
+ } else {
+ m_updated.call(instance, new Object[]{props});
+ }
+ } catch (Exception e) {
+ error("Cannot call the updated method " + m_updated.getMethod() + " : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Managed Service method.
+ * This method is called when the instance is reconfigured by the ConfigurationAdmin.
+ * When called, it must hold the monitor lock.
+ *
+ * @param conf : pushed configuration.
+ * @throws org.osgi.service.cm.ConfigurationException
+ * the reconfiguration failed.
+ * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
+ */
+ public void updated(Dictionary conf) throws org.osgi.service.cm.ConfigurationException {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ synchronized (this) {
+ if (conf == null && !m_configurationAlreadyPushed) {
+ return; // First call
+ } else if (conf != null) { // Configuration push
+ Properties props = reconfigureProperties(conf);
+ propagate(props, m_propagatedFromCA);
+ m_propagatedFromCA = props;
+ m_configurationAlreadyPushed = true;
+ } else if (m_configurationAlreadyPushed) { // Configuration deletion
+ propagate(null, m_propagatedFromCA);
+ m_propagatedFromCA = null;
+ m_configurationAlreadyPushed = false;
+ }
+
+ if (getInstanceManager().getPojoObjects() != null) {
+ try {
+ notifyUpdated(null);
+ } catch (Throwable e) {
+ error("Cannot call the updated method : " + e.getMessage(), e);
+ }
+ }
+ // Make a snapshot of the current configuration
+ for (Property p : m_configurableProperties) {
+ map.put(p.getName(), p.getValue());
+ }
+ }
+ notifyListeners(map);
+ }
+
+ /**
+ * Gets the configuration handler description.
+ *
+ * @return the configuration handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Add the given listener to the configuration handler's list of listeners.
+ *
+ * @param listener the {@code ConfigurationListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(ConfigurationListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("null listener");
+ }
+ synchronized (m_listeners) {
+ m_listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the given listener from the configuration handler's list of listeners.
+ * If the listeners is not registered, this method does nothing.
+ *
+ * @param listener the {@code ConfigurationListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void removeListener(ConfigurationListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("The list of listener is null");
+ }
+ synchronized (m_listeners) {
+ // We definitely cannot rely on listener's equals method...
+ // ...so we need to manually search for the listener, using ==.
+ ConfigurationListener found = null;
+ for (ConfigurationListener l : m_listeners) {
+ if (l == listener) {
+ found = l;
+ break;
+ }
+ }
+ if (found != null) {
+ m_listeners.remove(found);
+ }
+ }
+ }
+
+ /**
+ * Notify all listeners that a reconfiguration has occurred.
+ *
+ * @param map the new configuration of the component instance.
+ */
+ private void notifyListeners(Map<String, Object> map) {
+
+ // Get a snapshot of the listeners
+ // and check if we had a change in the map.
+ List<ConfigurationListener> tmp;
+ synchronized (m_listeners) {
+ tmp = new ArrayList<ConfigurationListener>(m_listeners);
+
+ if (map == null) {
+ if (m_lastConfiguration == null) {
+ // No change.
+ return;
+ }
+ // Else trigger the change.
+ } else {
+ if (m_lastConfiguration != null && m_lastConfiguration.size() == map.size()) {
+ // Must compare key by key
+ boolean diff = false;
+ for (String k : map.keySet()) {
+ if (! map.get(k).equals(m_lastConfiguration.get(k))) {
+ // Difference found, break;
+ diff = true;
+ break;
+ }
+ }
+ if (! diff) {
+ // no difference found, skip notification
+ return;
+ }
+ }
+ // Else difference found, triggers the change
+ }
+
+ if (map == null) {
+ m_lastConfiguration = Collections.emptyMap();
+ } else {
+ m_lastConfiguration = Collections.unmodifiableMap(map);
+ }
+
+ }
+ if (! tmp.isEmpty()) {
+ getLogger().log(Log.DEBUG, String.format(
+ "[%s] Notifying configuration listener: %s", getInstanceManager().getInstanceName(), tmp));
+ }
+ // Protect the map.
+ // Do notify, outside any lock
+ for (ConfigurationListener l : tmp) {
+ try {
+ l.configurationChanged(getInstanceManager(), m_lastConfiguration);
+ } catch (Throwable e) {
+ // Failure inside a listener: put a warning on the logger, and continue
+ warn(String.format(
+ "[%s] A ConfigurationListener has failed: %s",
+ getInstanceManager().getInstanceName(),
+ e.getMessage())
+ , e);
+ }
+ }
+ }
+
+ @Override
+ public void stateChanged(int state) {
+ if (state == ComponentInstance.DISPOSED) {
+ // Clean up the list of listeners
+ synchronized (m_listeners) {
+ m_listeners.clear();
+ }
+ }
+ super.stateChanged(state);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandlerDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandlerDescription.java
new file mode 100644
index 0000000..923f339
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandlerDescription.java
@@ -0,0 +1,152 @@
+/*
+ * 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.handlers.configuration;
+
+import java.util.List;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Property;
+
+/**
+ * Configuration handler description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConfigurationHandlerDescription extends HandlerDescription {
+
+ /**
+ * The property descriptions.
+ */
+ private PropertyDescription[] m_properties;
+
+ /**
+ * The Managed Service PID.
+ * <code>null</code> if not set.
+ */
+ private String m_pid;
+
+ /**
+ * The configuration handler.
+ */
+ private final ConfigurationHandler m_conf;
+
+ /**
+ * Creates the description object for the configuration handler description.
+ * @param handler the configuration handler.
+ * @param props the list of properties.
+ * @param pid the managed service pid or <code>null</code> if not set.
+ */
+ public ConfigurationHandlerDescription(ConfigurationHandler handler, List/*<Property>*/ props, String pid) {
+ super(handler);
+ m_conf = handler;
+ m_properties = new PropertyDescription[props.size()];
+ for (int i = 0; i < props.size(); i++) {
+ m_properties[i] = new PropertyDescription((Property) props.get(i));
+ }
+ m_pid = pid;
+ }
+
+ /**
+ * The handler information.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element elem = super.getHandlerInfo();
+
+ if (m_pid != null) {
+ elem.addAttribute(new Attribute("managed.service.pid", m_pid));
+ }
+
+ for (int i = 0; i < m_properties.length; i++) {
+ String name = m_properties[i].getName();
+ Object value = m_properties[i].getValue();
+ Element property = new Element("property", "");
+ elem.addElement(property);
+ if (name != null) {
+ property.addAttribute(new Attribute("name", name));
+ }
+ if (value != null) {
+ if (value == Property.NO_VALUE) {
+ property.addAttribute(new Attribute("value", "NO_VALUE"));
+ } else {
+ property.addAttribute(new Attribute("value", value.toString()));
+ }
+ }
+ }
+ return elem;
+ }
+
+ /**
+ * Gets the properties.
+ * @return the property set.
+ */
+ public PropertyDescription[] getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * Gets a property by name.
+ * @param name the property name
+ * @return the property description with the given name, {@code null} if there is no property with the given name.
+ * @since 1.11.0
+ */
+ public PropertyDescription getPropertyByName(String name) {
+ for (PropertyDescription desc :m_properties) {
+ if (name.equals(desc.getName())) {
+ return desc;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the managed service pid.
+ * @return the managed service pid of <code>null</code>
+ * if not set.
+ */
+ public String getManagedServicePid() {
+ return m_pid;
+ }
+
+ /**
+ * Add the given listener to the configuration handler's list of listeners.
+ *
+ * @param listener the {@code ConfigurationListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(ConfigurationListener listener) {
+ m_conf.addListener(listener);
+ }
+
+ /**
+ * Remove the given listener from the configuration handler's list of listeners.
+ *
+ * @param listener the {@code ConfigurationListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ * @throws java.util.NoSuchElementException if {@code listener} wasn't present the in configuration handler's list of listeners
+ */
+ public void removeListener(ConfigurationListener listener) {
+ m_conf.removeListener(listener);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationListener.java
new file mode 100644
index 0000000..aab13e4
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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.handlers.configuration;
+
+import org.apache.felix.ipojo.ComponentInstance;
+
+import java.util.Map;
+
+/**
+ * Listener interface for configuration updates of iPOJO component instances.
+ */
+public interface ConfigurationListener {
+
+ /**
+ * Called when the component instance is reconfigured.
+ *
+ * @param instance the concerned instance
+ * @param configuration snapshot of the instance configuration. Unmodifiable.
+ */
+ void configurationChanged(ComponentInstance instance, Map<String, Object> configuration);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/context/BundleContextHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/context/BundleContextHandler.java
new file mode 100644
index 0000000..cba7a80
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/context/BundleContextHandler.java
@@ -0,0 +1,192 @@
+/*
+ * 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.handlers.context;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.ConstructorInjector;
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Log;
+import org.osgi.framework.BundleContext;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+/**
+ * A handler injecting the bundle context in the implementation code.
+ *
+ * @since 1.11.2
+ */
+public class BundleContextHandler extends PrimitiveHandler {
+
+ private List<BundleCallback> m_methods = new ArrayList<BundleCallback>();
+
+ private BundleContext getComponentBundleContext() {
+ return getFactory().getBundleContext();
+ }
+
+ private BundleContext getInstanceBundleContext() {
+ return getInstanceManager().getInstanceContext();
+ }
+
+ /**
+ * Configures the handler.
+ * This method collects all `context` element.
+ *
+ * @param metadata the metadata of the component
+ * @param configuration the instance configuration
+ * @throws org.apache.felix.ipojo.ConfigurationException if the metadata are not correct.
+ */
+ @Override
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ Element[] contexts = metadata.getElements("context");
+ for (Element element : contexts) {
+ BundleContext bc = getBundleContextForConfiguration(element);
+
+ if (element.containsAttribute("constructor-parameter")) {
+ String idx = element.getAttribute("constructor-parameter");
+ int index = Integer.parseInt(idx);
+ final BundleContext injected = bc;
+ getLogger().log(Log.DEBUG, "Registering bundle context injection for index " + index + " for instance" +
+ " " + getInstanceManager().getInstanceName());
+ getInstanceManager().register(index, new ConstructorInjector() {
+
+ public Object getConstructorParameter(int index) {
+ return injected;
+ }
+
+ public Class getConstructorParameterType(int index) {
+ return BundleContext.class;
+ }
+ });
+ } else if (element.containsAttribute("field")) {
+ String field = element.getAttribute("field");
+ final BundleContext injected = bc;
+ FieldMetadata fm = getFactory().getPojoMetadata().getField(field);
+ if (fm == null) {
+ throw new ConfigurationException("Cannot inject the bundle context in the field " + field + " - " +
+ "reason: the field does not exist in " + getInstanceManager().getClassName());
+ }
+ if (!BundleContext.class.getName().equals(fm.getFieldType())) {
+ throw new ConfigurationException("Cannot inject the bundle context in the field " + field + " - " +
+ "reason: the field " + field + " from " + getInstanceManager().getClassName() + " is not " +
+ "from the BundleContext type");
+ }
+ getInstanceManager().register(fm, new FieldInterceptor() {
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Do nothing.
+ }
+
+ public Object onGet(Object pojo, String fieldName, Object value) {
+ return injected;
+ }
+ });
+ } else if (element.containsAttribute("method")) {
+ String method = element.getAttribute("method");
+ MethodMetadata mm = getFactory().getPojoMetadata().getMethod(method,
+ new String[]{BundleContext.class.getName()});
+ if (mm == null) {
+ getLogger().log(Log.WARNING, "Cannot find the method " + method + " in the class " +
+ getInstanceManager().getClassName() + ", super classes lookup will be attempted");
+ }
+ Callback callback = new Callback(method, new Class[]{BundleContext.class}, false,
+ getInstanceManager());
+ m_methods.add(new BundleCallback(callback, bc));
+ }
+
+
+ }
+ }
+
+ private BundleContext getBundleContextForConfiguration(Element element) throws ConfigurationException {
+ String type = element.getAttribute("value");
+ if (type == null) {
+ // XML case.
+ type = element.getAttribute("context");
+ }
+ BundleContext context;
+ if ("INSTANCE".equalsIgnoreCase(type)) {
+ context = getInstanceBundleContext();
+ } else if (type == null || "COMPONENT".equalsIgnoreCase(type)) {
+ context = getComponentBundleContext();
+ } else {
+ throw new ConfigurationException("Not supported bundle context source : " + type);
+ }
+ return context;
+ }
+
+ /**
+ * Stops the handler
+ * This method stops the management.
+ */
+ @Override
+ public void stop() {
+ // Nothing to do.
+ }
+
+ /**
+ * Starts the handler
+ * This method starts the management.
+ */
+ @Override
+ public void start() {
+ // Nothing to do.
+ }
+
+ /**
+ * Callback method called when an instance of the component is created, but
+ * before someone can use it.
+ * Injects the bundle context in all declared bundle callbacks.
+ *
+ * @param instance the created instance
+ */
+ @Override
+ public void onCreation(Object instance) {
+ for (BundleCallback callback : m_methods) {
+ try {
+ callback.invoke(instance);
+ } catch (Throwable e) {
+ error("Cannot inject the bundle context in the method " + callback.callback.getMethod() + " - reason:" +
+ " " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class BundleCallback {
+ private final Callback callback;
+ private final BundleContext context;
+
+ public BundleCallback(Callback callback, BundleContext injected) {
+ this.callback = callback;
+ this.context = injected;
+ }
+
+ public void invoke(Object target) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ if (context != null) {
+ callback.call(target, new Object[]{context});
+ }
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java
new file mode 100644
index 0000000..56ba6ec
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java
@@ -0,0 +1,41 @@
+/*
+ * 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.handlers.dependency;
+
+import java.util.*;
+
+/**
+ * An enumeration listing the different possibility to inject an aggregate dependency in a field or constructor
+ * parameter.
+ */
+public enum AggregateDependencyInjectionType {
+
+ ARRAY,
+ LIST,
+ SET,
+ VECTOR;
+
+ public static List<String> AGGREGATE_TYPES =
+ Arrays.asList(
+ List.class.getName(),
+ Vector.class.getName(),
+ Set.class.getName(),
+ Collection.class.getName());
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
new file mode 100644
index 0000000..27dba37
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -0,0 +1,1259 @@
+/*
+ * 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.handlers.dependency;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.handlers.dependency.ServiceUsage.Usage;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.Log;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * Represent a service dependency of the component instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Dependency extends DependencyModel implements FieldInterceptor, MethodInterceptor,
+ ConstructorInjector {
+
+ /**
+ * Reference on the Dependency Handler.
+ */
+ private final DependencyHandler m_handler;
+ /**
+ * Field of the dependency.
+ */
+ private final String m_field;
+ /**
+ * Default-Implementation.
+ */
+ private final String m_di;
+ /**
+ * Exception to throw when no providers are available.
+ */
+ private final String m_exception;
+ /**
+ * Is the Nullable pattern enabled?
+ */
+ private final boolean m_supportNullable;
+ /**
+ * List of dependency callback.
+ * Immutable once set.
+ */
+ private DependencyCallback[] m_callbacks;
+ /**
+ * Is the dependency a service level dependency.
+ * Immutable once set.
+ */
+ private boolean m_isServiceLevelRequirement;
+ /**
+ * Is the provider set frozen ?
+ */
+ private boolean m_isFrozen;
+ /**
+ * Is the dependency started ?
+ */
+ private boolean m_isStarted;
+ /**
+ * Thread Local.
+ */
+ private ServiceUsage m_usage;
+ /**
+ * Type of the object to inject in aggregate dependency. This value is used to determine what kind of object need
+ * to be injected for fields and constructor parameter for aggregate dependencies.
+ * Cannot change once set.
+ */
+ private AggregateDependencyInjectionType m_type;
+ /**
+ * Nullable object.
+ * Immutable once set.
+ */
+ private Object m_nullable;
+ /**
+ * Id of the dependency.
+ * Immutable once set.
+ */
+ private String m_id;
+ /**
+ * Do we have to inject proxy?
+ */
+ private boolean m_isProxy;
+ /**
+ * Proxy Object.
+ */
+ private Object m_proxyObject;
+ /**
+ * Constructor parameter index.
+ * -1 if not used.
+ */
+ private int m_index = -1;
+
+ /**
+ * The dependency timeout.
+ */
+ private int m_timeout;
+
+ /**
+ * Dependency constructor. After the creation the dependency is not started.
+ *
+ * @param handler : the dependency handler managing this dependency
+ * @param field : field of the dependency
+ * @param spec : required specification
+ * @param filter : LDAP filter of the dependency
+ * @param isOptional : is the dependency an optional dependency ?
+ * @param isAggregate : is the dependency an aggregate dependency
+ * @param nullable : describe if the nullable ability is enable or disable
+ * @param isProxy : is the proxied dependency
+ * @param identity : id of the dependency, may be null
+ * @param context : bundle context (or service context) to use.
+ * @param policy : resolution policy
+ * @param cmp : comparator to sort references
+ * @param defaultImplementation : default-implementation class
+ */
+ public Dependency(DependencyHandler handler, String field, Class spec, Filter filter, boolean isOptional,
+ boolean isAggregate, boolean nullable, boolean isProxy, String identity, BundleContext context,
+ int policy, Comparator cmp, String defaultImplementation, String exception) {
+ super(spec, isAggregate, isOptional, filter, cmp, policy, context, handler, handler.getInstanceManager());
+ m_handler = handler;
+ m_field = field;
+ m_isProxy = isProxy;
+
+ if (field != null) {
+ m_usage = new ServiceUsage();
+ } else {
+ m_usage = null;
+ }
+
+ m_supportNullable = nullable;
+ m_di = defaultImplementation;
+ m_exception = exception;
+
+ if (identity == null) {
+ if (spec != null) {
+ m_id = spec.getName();
+ }
+ } else {
+ m_id = identity;
+ }
+
+ // Else wait the setSpecification call.
+ }
+
+ /**
+ * Set the specification of the current dependency.
+ * In order to store the id of the dependency, this
+ * method is override. This method is called during the
+ * configuration.
+ *
+ * @param spec : request service Class
+ * @see org.apache.felix.ipojo.util.DependencyModel#setSpecification(java.lang.Class)
+ */
+ public void setSpecification(Class spec) {
+ super.setSpecification(spec);
+ if (m_id == null) {
+ m_id = spec.getName();
+ }
+ }
+
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * Add a callback to the dependency.
+ * This method is called during the configuration.
+ *
+ * @param callback : callback to add
+ */
+ protected void addDependencyCallback(DependencyCallback callback) {
+ if (m_callbacks == null) {
+ m_callbacks = new DependencyCallback[]{callback};
+ } else {
+ DependencyCallback[] newCallbacks = new DependencyCallback[m_callbacks.length + 1];
+ System.arraycopy(m_callbacks, 0, newCallbacks, 0, m_callbacks.length);
+ newCallbacks[m_callbacks.length] = callback;
+ m_callbacks = newCallbacks;
+ }
+ }
+
+ protected void addConstructorInjection(int index) throws ConfigurationException {
+ m_index = index;
+ m_usage = new ServiceUsage();
+ m_handler.getInstanceManager().register(index, this);
+ }
+
+ /**
+ * Stop the current dependency.
+ *
+ * @see org.apache.felix.ipojo.util.DependencyModel#stop()
+ */
+ public void stop() {
+ acquireWriteLockIfNotHeld();
+ m_isStarted = false;
+ super.stop();
+ releaseWriteLockIfHeld();
+
+ }
+
+ public DependencyHandler getHandler() {
+ return m_handler;
+ }
+
+ public boolean isFrozen() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_isFrozen;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Unfreeze the dependency.
+ *
+ * @see org.apache.felix.ipojo.util.DependencyModel#unfreeze()
+ */
+ public void unfreeze() {
+ try {
+ acquireWriteLockIfNotHeld();
+ m_isFrozen = false;
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ /**
+ * Call the bind method.
+ *
+ * @param pojo : pojo instance on which calling the bind method.
+ */
+ protected void onObjectCreation(Object pojo) {
+
+ ServiceReference[] refs;
+ try {
+ acquireWriteLockIfNotHeld();
+ if (!m_isStarted) {
+ return;
+ }
+
+ // We are notified of an instance creation, we have to freeze when the static policy is used
+ if (getBindingPolicy() == STATIC_BINDING_POLICY) {
+ m_isFrozen = true;
+ }
+
+ // Check optional case : nullable object case : do not call bind on nullable object
+ if (isOptional() && getSize() == 0) {
+ return;
+ }
+
+ refs = getServiceReferences(); // Stack confinement.
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+
+ // This is a pretty strange case, but we don't have any service.
+ // This may happen during refresh.
+ // So we just return.
+ if (refs == null) {
+ return;
+ }
+
+ // Call bind callback.
+ for (int j = 0; m_callbacks != null && j < m_callbacks.length; j++) { // The array is constant.
+ if (m_callbacks[j].getMethodType() == DependencyCallback.BIND) {
+ if (isAggregate()) {
+ for (ServiceReference ref : refs) {
+ Object svc = getService(ref);
+ if (svc != null) {
+ invokeCallback(m_callbacks[j], ref, svc, pojo);
+ } else {
+ // The service left already, or the service object cannot be created.
+ // We consider it as a departure.
+ m_serviceReferenceManager.removedService(ref, null);
+ }
+ }
+ } else {
+ // Take the first reference.
+ Object svc = getService(refs[0]);
+ if (svc != null) {
+ invokeCallback(m_callbacks[j], refs[0], svc, pojo);
+ } else {
+ // The service left already, or the service object cannot be created.
+ // We consider it as a departure.
+ m_serviceReferenceManager.removedService(refs[0], null);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Call unbind callback method.
+ *
+ * @param ref : reference to send (if accepted) to the method
+ */
+ private void callUnbindMethod(ServiceReference ref) {
+ if (m_handler.getInstanceManager().getState() > InstanceManager.STOPPED && m_handler.getInstanceManager().getPojoObjects() != null) {
+ for (int i = 0; m_callbacks != null && i < m_callbacks.length; i++) {
+ if (m_callbacks[i].getMethodType() == DependencyCallback.UNBIND) {
+ invokeCallback(m_callbacks[i], ref, getService(ref, false), null); // Call on each created pojo objects.
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method calling the given callback.
+ *
+ * @param callback : callback to call.
+ * @param ref : service reference.
+ * @param svcObject : the service object
+ * @param pojo : pojo on which calling the callback, if null call on each created pojo objects.
+ */
+ private void invokeCallback(DependencyCallback callback, ServiceReference ref, Object svcObject, Object pojo) {
+ try {
+ if (pojo == null) {
+ callback.call(ref, svcObject);
+ } else {
+ callback.callOnInstance(pojo, ref, svcObject);
+ }
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The method " + callback.getMethodName() + " does not exist in the implementation class " + m_handler.getInstanceManager().getClassName(), e);
+ m_handler.getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The method " + callback.getMethodName() + " is not accessible in the implementation class " + m_handler.getInstanceManager().getClassName(), e);
+ m_handler.getInstanceManager().stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The method " + callback.getMethodName() + " in the implementation class " + m_handler.getInstanceManager().getClassName() + " throws an exception : " + e.getTargetException().getMessage(), e.getTargetException());
+ m_handler.getInstanceManager().stop();
+ }
+
+ }
+
+ /**
+ * Call 'modify' method with the service reference in parameter (if accepted).
+ *
+ * @param ref : the service reference of the modified service
+ */
+ private void callModifyMethod(ServiceReference ref) {
+ if (m_handler.getInstanceManager().getState() > InstanceManager.STOPPED && m_handler.getInstanceManager().getPojoObjects() != null) {
+ for (int i = 0; m_callbacks != null && i < m_callbacks.length; i++) {
+ if (m_callbacks[i].getMethodType() == DependencyCallback.MODIFIED) {
+ invokeCallback(m_callbacks[i], ref, getService(ref), null); // Call on each created pojo objects.
+ }
+ }
+ }
+ }
+
+ /**
+ * Call method with the service reference in parameter (if accepted).
+ *
+ * @param ref : the service reference of the new service
+ */
+ private void callBindMethod(ServiceReference ref) {
+ // call bind method :
+ // if (m_handler.getInstanceManager().getState() == InstanceManager.VALID) {
+ if (m_handler.getInstanceManager().getState() > InstanceManager.STOPPED && m_handler.getInstanceManager().getPojoObjects() != null) {
+ for (int i = 0; m_callbacks != null && i < m_callbacks.length; i++) {
+ if (m_callbacks[i].getMethodType() == DependencyCallback.BIND) {
+ Object svc = getService(ref);
+ if (svc != null) {
+ invokeCallback(m_callbacks[i], ref, svc, null);
+ } else {
+ // We can't get the service object (https://issues.apache.org/jira/browse/FELIX-3896).
+ // This is probably because the service is leaving.
+ // We consider it as a departure.
+ m_serviceReferenceManager.removedService(ref, null);
+ }
+ }
+ }
+ }
+ }
+
+ private RuntimeException createExceptionToThrow() {
+ final String message = "No service available for " + DependencyHandler.getDependencyIdentifier(this);
+ if (m_exception == null) {
+ // Should never happen, but let's see.
+ return new RuntimeException(message);
+ }
+ try {
+ Class<RuntimeException> exceptionClass = (Class<RuntimeException>) getBundleContext()
+ .getBundle().loadClass(m_exception);
+ // Check constructor
+ final Constructor<RuntimeException> constructor = exceptionClass.getConstructor(new Class[]{String.class});
+ if (constructor != null) {
+ return constructor.newInstance(message);
+ } else {
+ return exceptionClass.newInstance();
+ }
+ } catch (Exception e) {
+ m_handler.getLogger().log(Log.ERROR, "Cannot create the exception object for dependency " +
+ DependencyHandler.getDependencyIdentifier(this) + " : " + e.getMessage(), e);
+ }
+
+ return new RuntimeException(message);
+ }
+
+ private void createNullableObject() {
+ // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
+ // access to the service specification.
+ if ( ! getSpecification().isInterface()) {
+ getHandler().getLogger().log(Log.INFO, "Cannot create the nullable object for " + getSpecification()
+ .getName() + " - the specification is not an interface");
+ return;
+ }
+
+ try {
+ ClassLoader cl = new NullableClassLoader(
+ getHandler().getInstanceManager().getClazz().getClassLoader(),
+ findClassLoadersFromSpecification(getSpecification()));
+
+ m_nullable =
+ Proxy.newProxyInstance(cl, new Class[]{
+ getSpecification(), Nullable.class}, new NullableObject()); // NOPMD
+
+ } catch (NoClassDefFoundError e) {
+ // A NoClassDefFoundError is thrown if the specification uses a class not accessible by the actual instance.
+ // It generally comes from a missing import.
+ throw new IllegalStateException("Cannot create the Nullable object, a referenced class cannot be loaded", e);
+ } catch (Throwable e) { // Catch any other exception that can occurs
+ throw new IllegalStateException("Cannot create the Nullable object, an unexpected error occurs", e);
+ }
+ }
+
+ private List<ClassLoader> findClassLoadersFromSpecification(Class clazz) {
+ ArrayList<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
+ ClassLoader specificationCL = clazz.getClassLoader();
+ classLoaders.add(specificationCL);
+ // use Class.getMethods() to go thru the full hierarchy of classes of the specification
+ for (Method method : clazz.getMethods()) {
+ for (Class<?> parameterType : method.getParameterTypes()) {
+ ClassLoader parameterCL = parameterType.getClassLoader();
+ if (parameterCL != null && !classLoaders.contains(parameterCL)) {
+ classLoaders.add(parameterCL);
+ }
+ }
+ if (!Void.TYPE.equals(method.getReturnType())) {
+ ClassLoader returnCL = method.getReturnType().getClassLoader();
+ if (returnCL != null && !classLoaders.contains(returnCL)) {
+ classLoaders.add(returnCL);
+ }
+ }
+ }
+ return classLoaders;
+ }
+
+ /**
+ * Start the dependency.
+ */
+ public void start() {
+
+ if (isOptional() && !isAggregate()) {
+ if (m_di == null && m_exception == null) {
+ // If nullable are supported, create the nullable object.
+ if (m_supportNullable) {
+ createNullableObject();
+ }
+ } else if (m_di != null) {
+ // Create the default-implementation object.
+ try {
+ Class clazz = getHandler().getInstanceManager().getContext().getBundle().loadClass(m_di);
+ m_nullable = clazz.newInstance();
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Cannot load the default-implementation " + m_di, e);
+ } catch (InstantiationException e) {
+ throw new IllegalStateException("Cannot load the default-implementation " + m_di, e);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Cannot load the default-implementation " + m_di, e);
+ } catch (Throwable e) { // Catch any other exception
+ throw new IllegalStateException("Cannot load the default-implementation (unexpected exception) " + m_di, e);
+ }
+ }
+ }
+
+ if (m_isProxy) {
+ if (isAggregate()) {
+ if (m_type == AggregateDependencyInjectionType.SET) {
+ m_proxyObject = new ServiceSet(this);
+ } else {
+ m_proxyObject = new ServiceList(this);
+ }
+ } else {
+ // Can we really proxy ? We can proxy only interfaces.
+ if (getSpecification().isInterface()) {
+ String type = getHandler().getInstanceManager().getContext().getProperty(DependencyHandler.PROXY_TYPE_PROPERTY);
+
+ // If it's null we should check on the System directly, Felix delegates to it,
+ // but not other frameworks
+ if (type == null) {
+ type = System.getProperty(DependencyHandler.PROXY_TYPE_PROPERTY);
+ }
+
+ if (type == null || type.equals(DependencyHandler.SMART_PROXY)) {
+ SmartProxyFactory proxyFactory = new SmartProxyFactory(this.getClass().getClassLoader());
+ m_proxyObject = proxyFactory.getProxy(this);
+ } else {
+ DynamicProxyFactory proxyFactory = new DynamicProxyFactory();
+ m_proxyObject = proxyFactory.getProxy(getSpecification());
+ }
+ } else {
+ m_handler.warn("Cannot create a proxy for a service dependency which is not an interface " +
+ "- disabling proxy for " + getId());
+ }
+ }
+ }
+
+ super.start();
+
+ // Once the dependency is started, access to fields must be protected.
+ acquireWriteLockIfNotHeld();
+ if (getBindingPolicy() == STATIC_BINDING_POLICY && m_handler.getInstanceManager().getPojoObjects() != null) {
+ m_isFrozen = true;
+ }
+ m_isStarted = true;
+ releaseWriteLockIfHeld();
+ }
+
+ protected DependencyCallback[] getCallbacks() {
+ return m_callbacks;
+ }
+
+ /**
+ * Set that this dependency is a service level dependency.
+ * This forces the scoping policy to be STRICT.
+ */
+ public void setServiceLevelDependency() {
+ m_isServiceLevelRequirement = true;
+ setBundleContext(new PolicyServiceContext(m_handler.getInstanceManager().getGlobalContext(), m_handler.getInstanceManager().getLocalServiceContext(), PolicyServiceContext.LOCAL));
+ }
+
+ public String getId() {
+ // No synchronization required, the id is constant.
+ return m_id;
+ }
+
+ public boolean isServiceLevelRequirement() {
+ return m_isServiceLevelRequirement;
+ }
+
+ /**
+ * A new service has to be injected.
+ *
+ * @param reference : the new matching service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceArrival(ServiceReference reference) {
+ callBindMethod(reference);
+ //The method is only called when a new service arrives, or when the used one is replaced.
+ }
+
+ /**
+ * An already injected service is modified.
+ *
+ * @param reference : the modified service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceModification(ServiceReference reference) {
+ callModifyMethod(reference);
+ }
+
+ /**
+ * A used (already injected) service disappears.
+ *
+ * @param ref : leaving service reference.
+ * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
+ */
+ public void onServiceDeparture(ServiceReference ref) {
+ callUnbindMethod(ref);
+ }
+
+ /**
+ * The dependency has been reconfigured.
+ * Call unbind method and then bind methods. If the dependency cache is not reset,
+ * the thread continues to get older services.
+ *
+ * @param departs : no more matching services.
+ * @param arrivals : new services
+ * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[])
+ */
+ public void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals) {
+ for (int i = 0; departs != null && i < departs.length; i++) {
+ callUnbindMethod(departs[i]);
+ }
+
+ for (int i = 0; arrivals != null && i < arrivals.length; i++) {
+ callBindMethod(arrivals[i]);
+ }
+ }
+
+ /**
+ * Reset the thread local cache if used.
+ * For testing purpose only.
+ */
+ public void resetLocalCache() {
+ if (m_usage != null) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ createServiceObject(usage);
+ }
+ }
+ }
+
+ /**
+ * Get the used service references list.
+ *
+ * @return the used service reference or null if no service reference are available.
+ */
+ public List<ServiceReference> getServiceReferencesAsList() {
+ ServiceReference[] refs = super.getServiceReferences();
+ if (refs == null) {
+ return null;
+ } else {
+ return Arrays.asList(refs);
+ }
+ }
+
+
+ /**
+ * Gets the list of callbacks attached to the current dependency.
+ * @return the array of dependency callback, {@code null} if no callbacks are attached to the current dependency.
+ */
+ public DependencyCallback[] getDependencyCallbacks() {
+ return m_callbacks;
+ }
+
+
+ /**
+ * Called by the proxy to get service objects to delegate a method.
+ * On aggregate dependencies, it returns a list.
+ *
+ * @return a service object or a nullable/default-implementation object.
+ * For aggregate dependencies it returns a list or an empty list.
+ */
+ public Object getService() {
+ // Check that we're in proxy mode.
+ if (!m_isProxy) {
+ throw new IllegalStateException("The dependency has not enabled the `proxy` mode.");
+ }
+
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack == 0) { // uninitialized usage.
+ if (usage.m_componentStack > 0) {
+ // We comes from the component who didn't touch the service.
+ // So we initialize the usage.
+ createServiceObject(usage);
+ usage.inc(); // Start the caching, so set the stack level to 1
+ m_usage.set(usage); // Required by Dalvik.
+ if (isAggregate()) {
+ Object obj = usage.m_object;
+ if (obj instanceof Set) {
+ List<Object> list = new ArrayList<Object>();
+ list.addAll((Set) obj);
+ return list;
+ } else {
+ // We already have a list
+ return obj;
+ }
+ } else {
+ return usage.m_object;
+ }
+ } else {
+ // External access => Immediate get.
+ if (isAggregate()) {
+ ServiceReference[] refs = getServiceReferences();
+ if (refs == null) {
+ return new ArrayList(0); // Create an empty list.
+ } else {
+ List<Object> objs = new ArrayList<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ return objs;
+ }
+ } else { // Scalar dependency.
+ ServiceReference ref = getServiceReference();
+ if (ref != null) {
+ return getService(ref);
+ } else {
+ // No service available.
+ // TODO Decide what we have to do.
+ throw new RuntimeException("Service " + getSpecification() + " unavailable");
+ }
+ }
+ }
+ } else {
+ // Use the copy.
+ // if the copy is a set, transform to a list
+ if (isAggregate()) {
+ Object obj = usage.m_object;
+ if (obj instanceof Set) {
+ List<Object> list = new ArrayList<Object>();
+ list.addAll((Set) obj);
+ return list;
+ } else {
+ // We already have a list
+ return obj;
+ }
+ } else {
+ return usage.m_object;
+ }
+
+ }
+ }
+
+ /**
+ * This method is called by the replaced code in the component
+ * implementation class. Construct the service object list is necessary.
+ *
+ * @param pojo : POJO object.
+ * @param fieldName : field
+ * @param value : last value.
+ * @return the service object or a nullable / default implementation if defined.
+ * @see org.apache.felix.ipojo.FieldInterceptor#onGet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+
+ // Initialize the thread local object is not already touched.
+ Usage usage = m_usage.get();
+ if (usage.m_stack == 0) { // uninitialized usage.
+ createServiceObject(usage);
+ usage.inc(); // Start the caching, so set the stack level to 1
+ m_usage.set(usage); // Required by Dalvik
+ }
+ if (!m_isProxy) {
+ return usage.m_object;
+ } else {
+ return m_proxyObject;
+ }
+
+ }
+
+ /**
+ * Creates the object to store in the given Thread Local.
+ * This object will be injected inside the POJO field.
+ *
+ * @param usage : Thread Local to populate.
+ */
+ private void createServiceObject(Usage usage) {
+ ServiceReference[] refs = getServiceReferences();
+
+ // manage timeout
+ if (refs == null) {
+ waitForServiceUntilTimeout();
+ }
+
+ refs = getServiceReferences();
+
+ if (!isAggregate()) {
+ if (refs == null) {
+ if (m_exception != null) {
+ // Throw the exception.
+ throw createExceptionToThrow();
+ }
+
+ if (m_nullable == null && m_supportNullable) {
+ m_handler.warn("[" + m_handler.getInstanceManager().getInstanceName() + "] The dependency is not optional, however no service object can be injected in " + m_field + " -> " + getSpecification().getName());
+ createNullableObject();
+ }
+ usage.m_object = m_nullable; // Add null if the Nullable pattern is disabled.
+ } else {
+ ServiceReference ref = getServiceReference();
+ usage.m_object = getService(ref);
+ }
+ } else {
+ switch(m_type) {
+ case ARRAY:
+ try {
+ if (refs == null) {
+ usage.m_object = (Object[]) Array.newInstance(getSpecification(), 0); // Create an empty array.
+ } else {
+ // Use a reflective construction to avoid class cast exception. This method allows setting the component type.
+ Object[] objs = (Object[]) Array.newInstance(getSpecification(), refs.length);
+ for (int i = 0; i < refs.length; i++) {
+ ServiceReference ref = refs[i];
+ objs[i] = getService(ref);
+ }
+ usage.m_object = objs;
+ }
+ } catch (ArrayStoreException e) {
+ throw new RuntimeException("Cannot create the array - Check that the bundle can access the service interface", e);
+ }
+ break;
+ case LIST:
+ if (refs == null) {
+ usage.m_object = Collections.emptyList();
+ } else {
+ // Use a list to store service objects
+ List<Object> objs = new ArrayList<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ usage.m_object = objs;
+ }
+ break;
+ case SET:
+ if (refs == null) {
+ usage.m_object = Collections.emptySet();
+ } else {
+ // Use a vector to store service objects
+ Set<Object> objs = new HashSet<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ usage.m_object = objs;
+ }
+ break;
+ case VECTOR:
+ if (refs == null) {
+ usage.m_object = new Vector(0); // Create an empty vector.
+ } else {
+ // Use a vector to store service objects
+ Vector<Object> objs = new Vector<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ usage.m_object = objs;
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Waits a service providers. The wait stops when the timeout is reached.
+ */
+ private void waitForServiceUntilTimeout() {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+
+ // We used a synchronized block here because we must hold the monitor lock during the 'wait'
+ synchronized (this) {
+ while (getServiceReference() == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_timeout;
+ }
+ }
+ }
+ // When this method exit, the check will be done...
+ }
+
+ /**
+ * The field was set.
+ * This method should not be call if the POJO is written correctly.
+ *
+ * @param pojo : POJO object
+ * @param fieldName : field name
+ * @param value : set value.
+ * @see org.apache.felix.ipojo.FieldInterceptor#onSet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Nothing to do.
+ }
+
+ /**
+ * A POJO method will be invoked.
+ *
+ * @param pojo : Pojo object
+ * @param method : called method
+ * @param args : arguments
+ * @see org.apache.felix.ipojo.MethodInterceptor#onEntry(java.lang.Object, java.lang.reflect.Member, java.lang.Object[])
+ */
+ public void onEntry(Object pojo, Member method, Object[] args) {
+ if (m_usage != null) {
+ Usage usage = m_usage.get();
+ usage.incComponentStack(); // Increment the number of component access.
+ if (usage.m_stack > 0) {
+ usage.inc();
+ m_usage.set(usage); // Set the Thread local as value has been modified
+ }
+ }
+ }
+
+ /**
+ * A POJO method has thrown an error.
+ * This method does nothing and wait for the finally.
+ *
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @param throwable : thrown error
+ * @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Member, java.lang.Throwable)
+ */
+ public void onError(Object pojo, Member method, Throwable throwable) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method has returned.
+ *
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @param returnedObj : returned object (null for void method)
+ * @see org.apache.felix.ipojo.MethodInterceptor#onExit(java.lang.Object, java.lang.reflect.Member, java.lang.Object)
+ */
+ public void onExit(Object pojo, Member method, Object returnedObj) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method is finished.
+ *
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @see org.apache.felix.ipojo.MethodInterceptor#onFinally(java.lang.Object, java.lang.reflect.Member)
+ */
+ public void onFinally(Object pojo, Member method) {
+ if (m_usage != null) {
+ Usage usage = m_usage.get();
+ usage.decComponentStack();
+ if (usage.m_stack > 0) {
+ if (usage.dec()) {
+ // Exit the method flow => Release all objects
+ usage.clear();
+ // Also remove the thread local object.
+ m_usage.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets true if the dependency use Nullable objects.
+ *
+ * @return true if the dependency is optional and supports nullable objects.
+ */
+ public boolean supportsNullable() {
+ return isOptional()
+ && ! isAggregate()
+ && m_supportNullable;
+ }
+
+ public String getDefaultImplementation() {
+ return m_di;
+ }
+
+ public boolean isProxy() {
+ return m_isProxy;
+ }
+
+ public void setProxy(boolean proxy) {
+ m_isProxy = proxy;
+ }
+
+ /**
+ * Set the type to inject.
+ * This method set the dependency as aggregate.
+ *
+ * @param type the type to inject.
+ */
+ protected void setAggregateType(AggregateDependencyInjectionType type) {
+ setAggregate(true);
+ m_type = type;
+ }
+
+ /**
+ * Sets the dependency timeout.
+ *
+ * @param timeout the timeout in ms.
+ */
+ public void setTimeout(int timeout) {
+ m_timeout = timeout;
+ }
+
+ /**
+ * Gets the constructor parameter.
+ *
+ * @return the index of the constructor parameter,
+ * or <code>-1</code> if not set.
+ */
+ public int getConstructorParameterIndex() {
+ return m_index;
+ }
+
+ /**
+ * Gets the object to inject in the constructor parameter.
+ *
+ * @param index the index of the parameter
+ * @return the created proxy object
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
+ */
+ public Object getConstructorParameter(int index) {
+ if (m_index == index && m_proxyObject != null) {
+ return m_proxyObject;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the type of the constructor parameter.
+ *
+ * @param index the parameter index
+ * @return the class of the object. For scalar dependency, it's the
+ * specification, for aggregate it depends of the container object:
+ * {@link List} or {@link Set}.
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
+ */
+ public Class getConstructorParameterType(int index) {
+ if (m_index == index && m_proxyObject != null) {
+ if (isAggregate()) {
+ switch (m_type) {
+ case LIST:
+ return List.class;
+ case SET:
+ return Set.class;
+ default:
+ return null; // Should never happen, it was checked before.
+ }
+ } else {
+ return getSpecification();
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public String getException() {
+ return m_exception;
+ }
+
+ public int getTimeout() {
+ return m_timeout;
+ }
+
+ public AggregateDependencyInjectionType getAggregateType() {
+ return m_type;
+ }
+
+ /**
+ * Classloader for nullable objects.
+ */
+ private static class NullableClassLoader extends ClassLoader {
+ /**
+ * Component classloader.
+ */
+ private ClassLoader m_component;
+ /**
+ * Specification classloaders.
+ */
+ private List<ClassLoader> m_classLoadersFromSpecification;
+
+ /**
+ * Creates a NullableClassLoader.
+ * @param cmp the component class loader.
+ * @param classLoadersFromSpecification the specification class loader plus the ones referenced by parameters and return types.
+ */
+ public NullableClassLoader(ClassLoader cmp, List<ClassLoader> classLoadersFromSpecification) {
+ m_component = cmp;
+ m_classLoadersFromSpecification = classLoadersFromSpecification;
+ }
+
+ /**
+ * Loads the given class.
+ * This method uses the classloader of the component class
+ * and (if not found) the specification classloaders.
+ * Throws the last {@link ClassNotFoundException} caught while trying
+ * to load the class from the specifiation classloaders
+ *
+ * @param name the class name
+ * @return the class object
+ * @throws ClassNotFoundException if the class is not found by the classloaders.
+ * @see java.lang.ClassLoader#loadClass(java.lang.String)
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+ try {
+ return m_component.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ ClassNotFoundException lastCaught = null;
+ for (ClassLoader classLoader : m_classLoadersFromSpecification) {
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException cnfe) {
+ lastCaught = cnfe;
+ }
+ }
+ throw lastCaught;
+ }
+ }
+ }
+
+ /**
+ * Creates smart proxy object for proxied scalar dependencies.
+ */
+ private class SmartProxyFactory extends ClassLoader {
+
+ /**
+ * Handler classloader, used to load the temporal dependency class.
+ */
+ private ClassLoader m_handlerCL;
+
+ /**
+ * Creates the proxy classloader.
+ *
+ * @param parent the handler classloader.
+ */
+ public SmartProxyFactory(ClassLoader parent) {
+ super(getHandler().getInstanceManager().getFactory().getBundleClassLoader());
+ m_handlerCL = parent;
+ }
+
+ /**
+ * Loads a proxy class generated for the given (interface) class.
+ *
+ * @param clazz the service specification to proxy
+ * @return the Class object of the proxy.
+ */
+ protected Class getProxyClass(Class clazz) {
+ byte[] clz = ProxyGenerator.dumpProxy(clazz); // Generate the proxy.
+ // Turn around the VM changes (FELIX-2716) about java.* classes.
+ String cn = clazz.getName();
+ if (cn.startsWith("java.")) {
+ cn = "$" + cn;
+ }
+ return defineClass(cn + "$$Proxy", clz, 0, clz.length);
+ }
+
+ /**
+ * Create a proxy object for the given specification. The proxy
+ * uses the given dependency to get the service object.
+ *
+ * @param dep the dependency used to get the service
+ * @return the proxy object.
+ */
+ public Object getProxy(Dependency dep) {
+ try {
+ Class clazz = getProxyClass(getSpecification());
+ Constructor constructor = clazz.getConstructor(
+ new Class[]{clazz.getClassLoader().loadClass(Dependency.class.getName())});
+ return constructor.newInstance(new Object[]{dep});
+ } catch (Throwable e) {
+ m_handler.error("Cannot create the proxy object", e);
+ m_handler.getInstanceManager().stop();
+ return null;
+ }
+ }
+
+ /**
+ * Loads the given class.
+ * This method uses the classloader of the specification class
+ * or the handler class loader.
+ *
+ * @param name the class name
+ * @return the class object
+ * @throws ClassNotFoundException if the class is not found by the two classloaders.
+ * @see java.lang.ClassLoader#loadClass(java.lang.String)
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+ try {
+ return getHandler().getInstanceManager().getContext().getBundle().loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return m_handlerCL.loadClass(name);
+ }
+ }
+ }
+
+ /**
+ * Creates java dynamic proxy object for proxied scalar dependencies.
+ */
+ private class DynamicProxyFactory implements InvocationHandler {
+
+ /**
+ * HashCode method.
+ */
+ private Method m_hashCodeMethod;
+ /**
+ * Equals method.
+ */
+ private Method m_equalsMethod;
+ /**
+ * toStirng method.
+ */
+ private Method m_toStringMethod;
+
+ /**
+ * Creates a DynamicProxyFactory.
+ */
+ public DynamicProxyFactory() {
+ try {
+ m_hashCodeMethod = Object.class.getMethod("hashCode", null);
+ m_equalsMethod = Object.class
+ .getMethod("equals", new Class[]{Object.class});
+ m_toStringMethod = Object.class.getMethod("toString", null);
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a proxy object for the given specification. The proxy
+ * uses the given dependency to get the service object.
+ *
+ * @param spec the service specification (interface)
+ * @return the proxy object.
+ */
+ public Object getProxy(Class spec) {
+ return java.lang.reflect.Proxy.newProxyInstance(
+ getHandler().getInstanceManager().getClazz().getClassLoader(),
+ new Class[]{spec},
+ this);
+ }
+
+ /**
+ * Invocation Handler delegating invocation on the
+ * service object.
+ *
+ * @param proxy the proxy object
+ * @param method the method
+ * @param args the arguments
+ * @return a proxy object.
+ * @throws Exception if the invocation throws an exception
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
+ Object svc = getService();
+ Class declaringClass = method.getDeclaringClass();
+ if (declaringClass == Object.class) {
+ if (method.equals(m_hashCodeMethod)) {
+ return this.hashCode();
+ } else if (method.equals(m_equalsMethod)) {
+ return proxy == args[0] ? Boolean.TRUE : Boolean.FALSE;
+ } else if (method.equals(m_toStringMethod)) {
+ return this.toString();
+ } else {
+ throw new InternalError(
+ "Unexpected Object method dispatched: " + method);
+ }
+ }
+
+ return method.invoke(svc, args);
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
new file mode 100644
index 0000000..a7b4c4b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
@@ -0,0 +1,319 @@
+/*
+ * 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.handlers.dependency;
+
+import org.apache.felix.ipojo.util.Callback;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * This class allwos the creation of callback when service dependency arrives or
+ * disappear.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DependencyCallback extends Callback {
+
+ /**
+ * Bind method (called when a service arrives).
+ */
+ public static final int BIND = 0;
+ /**
+ * Unbind method (called when a service disappears).
+ */
+ public static final int UNBIND = 1;
+ /**
+ * Updated method (called when a service is modified).
+ */
+ public static final int MODIFIED = 2;
+ /**
+ * Is the method a bind method or an unbind method ?
+ */
+ private int m_methodType;
+ /**
+ * Arguments of the callback.
+ */
+ private String[] m_argument;
+ /**
+ * Callback method name.
+ */
+ private String m_method;
+ /**
+ * Service Dependency.
+ */
+ private Dependency m_dependency;
+
+ /**
+ * Constructor.
+ *
+ * @param dep : the dependency attached to this dependency callback
+ * @param method : the method to call
+ * @param methodType : is the method to call a bind method or an unbind
+ * method
+ */
+ public DependencyCallback(Dependency dep, String method, int methodType) {
+ super(method, (String[]) null, false, dep.getHandler().getInstanceManager());
+ m_methodType = methodType;
+ m_dependency = dep;
+ m_method = method;
+ }
+
+ public int getMethodType() {
+ return m_methodType;
+ }
+
+ public String getMethodName() {
+ return m_method;
+ }
+
+ /**
+ * Set the argument type (Empty or the class name).
+ *
+ * @param arg : the array of argument types.
+ */
+ public void setArgument(String[] arg) {
+ m_argument = arg;
+ }
+
+ /**
+ * Search the method object in the POJO by analyzing present method.
+ * If not found in the pojo it tests the parent classes.
+ * The name of the method and the argument type are checked.
+ */
+ protected void searchMethod() {
+ if (m_argument != null) {
+ Method[] methods = m_dependency.getHandler().getInstanceManager().getClazz().getDeclaredMethods();
+ for (Method method : methods) {
+ // First check the method name
+ if (method.getName().equals(m_method)) {
+ // Check arguments
+ Class[] clazzes = method.getParameterTypes();
+ if (clazzes.length == m_argument.length) { // Test size to avoid useless loop // NOPMD
+ int argIndex = 0;
+ for (; argIndex < m_argument.length; argIndex++) {
+ if (!m_argument[argIndex].equals(clazzes[argIndex].getName())) {
+ break;
+ }
+ }
+ if (argIndex == m_argument.length) { // If the array was completely read.
+ m_methodObj = method; // It is the looked method.
+ if (!m_methodObj.isAccessible()) {
+ // If not accessible, try to set the accessibility.
+ m_methodObj.setAccessible(true);
+ }
+ return;
+ }
+ }
+
+ }
+ }
+ }
+
+ // Not found => Try parent method.
+ searchParentMethod();
+
+ if (m_methodObj == null) {
+ // If not found, stop the instance (fatal error)
+ m_dependency.getHandler().error("The dependency callback method " + m_method + " cannot be invoked - " +
+ "reason: the method is not defined in the component class (" + m_dependency.getHandler()
+ .getInstanceManager().getClazz().getName() + ")");
+ m_dependency.getHandler().getInstanceManager().stop();
+ } else {
+ if (!m_methodObj.isAccessible()) {
+ // If not accessible, try to set the accessibility.
+ m_methodObj.setAccessible(true);
+ }
+ }
+ }
+
+ /**
+ * Introspect parent class to find the method.
+ */
+ private void searchParentMethod() {
+ // look at parent classes
+ Method[] methods = m_dependency.getHandler().getInstanceManager().getClazz().getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ // First check the method name
+ if (methods[i].getName().equals(m_method)) {
+ // Check arguments
+ Class[] clazzes = methods[i].getParameterTypes();
+ switch (clazzes.length) {
+ case 0:
+ // Callback with no arguments.
+ m_methodObj = methods[i];
+ m_argument = new String[0];
+ return;
+ case 1:
+ // The callback receives a ServiceReference
+ if (clazzes[0].getName().equals(ServiceReference.class.getName())) {
+ // Callback with a service reference.
+ m_methodObj = methods[i];
+ m_argument = new String[]{ServiceReference.class.getName()};
+ return;
+ }
+ // The callback receives a Service object
+ if (clazzes[0].getName().equals(m_dependency.getSpecification().getName())) {
+ // Callback with the service object.
+ m_methodObj = methods[i];
+ m_argument = new String[]{m_dependency.getSpecification().getName()};
+ return;
+ }
+ break;
+ case 2:
+ // The callback receives the service object and the service reference
+ if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(ServiceReference.class.getName())) {
+ // Callback with two arguments.
+ m_methodObj = methods[i];
+ m_argument = new String[]{m_dependency.getSpecification().getName(), ServiceReference.class.getName()};
+ return;
+ }
+ // The callback receives the service object and the service properties (in a Map)
+ if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(Map.class.getName())) {
+ // Callback with two arguments.
+ m_methodObj = methods[i];
+ m_argument = new String[]{m_dependency.getSpecification().getName(), Map.class.getName()};
+ return;
+ }
+ // The callback receives the service object and the service properties (in a Dictionary)
+ if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(Dictionary.class.getName())) {
+ // Callback with two arguments.
+ m_methodObj = methods[i];
+ m_argument = new String[]{m_dependency.getSpecification().getName(), Dictionary.class.getName()};
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Call the callback method with a service reference.
+ *
+ * @param ref : the service reference to send to the method
+ * @param obj : the service object
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ protected void call(ServiceReference ref, Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ if (m_methodObj == null) {
+ searchMethod();
+ }
+ switch (m_argument.length) {
+ case 0:
+ call(new Object[0]);
+ break;
+ case 1:
+ if (m_argument[0].equals(ServiceReference.class.getName())) {
+ call(new Object[]{ref});
+ } else {
+ call(new Object[]{obj});
+ }
+ break;
+ case 2:
+ if (m_argument[1].equals(ServiceReference.class.getName())) {
+ call(new Object[]{obj, ref});
+ } else if (m_argument[1].equals(Dictionary.class.getName())) {
+ call(new Object[]{obj, getPropertiesInDictionary(ref)});
+ } else {
+ call(new Object[]{obj, getPropertiesInMap(ref)});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Creates a {@link Dictionary} containing service properties of the
+ * given service reference.
+ *
+ * @param ref the service reference
+ * @return a {@link Dictionary} containing the service properties.
+ */
+ private Dictionary getPropertiesInDictionary(ServiceReference ref) {
+ String[] keys = ref.getPropertyKeys(); // Can't be null
+ Dictionary dict = new Properties();
+ for (int i = 0; i < keys.length; i++) {
+ dict.put(keys[i], ref.getProperty(keys[i]));
+ }
+ return dict;
+ }
+
+ /**
+ * Creates a {@link Map} containing service properties of the
+ * given service reference.
+ *
+ * @param ref the service reference
+ * @return a {@link Map} containing the service properties.
+ */
+ private Map getPropertiesInMap(ServiceReference ref) {
+ String[] keys = ref.getPropertyKeys(); // Can't be null
+ Map map = new HashMap();
+ for (int i = 0; i < keys.length; i++) {
+ map.put(keys[i], ref.getProperty(keys[i]));
+ }
+ return map;
+ }
+
+ /**
+ * Call the callback on the given instance with the given argument.
+ *
+ * @param instance : the instance on which call the callback
+ * @param ref : the service reference to send to the callback
+ * @param obj : the service object
+ * @throws NoSuchMethodException : the method is not found
+ * @throws IllegalAccessException : the method could not be called
+ * @throws InvocationTargetException : an error happens in the called method
+ */
+ protected void callOnInstance(Object instance, ServiceReference ref, Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ if (m_methodObj == null) {
+ searchMethod();
+ }
+ switch (m_argument.length) {
+ case 0:
+ call(instance, new Object[0]);
+ break;
+ case 1:
+ if (m_argument[0].equals(ServiceReference.class.getName())) {
+ call(instance, new Object[]{ref});
+ } else {
+ call(instance, new Object[]{obj});
+ }
+ break;
+ case 2:
+ if (m_argument[1].equals(ServiceReference.class.getName())) {
+ call(instance, new Object[]{obj, ref});
+ } else if (m_argument[1].equals(Dictionary.class.getName())) {
+ call(instance, new Object[]{obj, getPropertiesInDictionary(ref)});
+ } else {
+ call(instance, new Object[]{obj, getPropertiesInMap(ref)});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java
new file mode 100644
index 0000000..ab84903
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java
@@ -0,0 +1,465 @@
+/*
+ * 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.handlers.dependency;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+/**
+ * Utility class checking the configuration of a dependency.
+ */
+public class DependencyConfigurationChecker {
+
+ public static void ensure(Dependency dependency, Element metadata, PojoMetadata manipulation) throws
+ ConfigurationException {
+ ensureThatAtLeastOneInjectionIsSpecified(dependency);
+ ensureThatTheFieldIsInComponentClass(dependency, manipulation);
+ ensureThatTheConstructorParameterIsCoherent(dependency, manipulation);
+ ensureThatCallbacksAreCoherent(dependency, manipulation);
+ deduceAggregationFromTheInjectionPoints(dependency, manipulation);
+ deduceTheServiceSpecification(dependency, manipulation);
+ checkTheServiceUnavailableAction(dependency, metadata);
+ checkTheConsistencyOfTheFromAttribute(dependency, metadata);
+ disableProxyForInconsistentTypes(dependency);
+ }
+
+ /**
+ * Disables the proxy settings for types that does not support it: Vector, Array, and non interface specification.
+ * If the dependency is disabled, check that we are no constructor injection.
+ * @param dependency the dependency
+ */
+ private static void disableProxyForInconsistentTypes(Dependency dependency) throws ConfigurationException {
+ if (! dependency.getSpecification().isInterface()
+ || dependency.isAggregate() && dependency.getAggregateType() == AggregateDependencyInjectionType.ARRAY
+ || dependency.isAggregate() && dependency.getAggregateType() == AggregateDependencyInjectionType.VECTOR) {
+ dependency.setProxy(false);
+ if (dependency.getConstructorParameterIndex() != -1) {
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " has an inconsistent configuration. - reason: the service specification " +
+ "or container do not support proxy, which is required for constructor injection");
+ }
+ dependency.getHandler().info("Proxy disabled for " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " - the service specification or container do not support proxy");
+ }
+ }
+
+ /**
+ * Checks that the dependency callbacks are consistent:
+ * <ul>
+ * <li>have a supported 'type'</li>
+ * <li>have a supported signature</li>
+ * </ul>
+ * If the method is not in the component class, a message is logged, as this verification cannot be used.
+ * If the method is found in the manipulation metadata, the callback parameters are set.
+ * @param dependency the dependency
+ * @param manipulation the manipulation
+ * @throws ConfigurationException if the methods do not obey to the previously mentioned rules.
+ */
+ private static void ensureThatCallbacksAreCoherent(Dependency dependency, PojoMetadata manipulation) throws
+ ConfigurationException {
+ DependencyCallback[] callbacks = dependency.getCallbacks();
+ if (callbacks != null) {
+ for (DependencyCallback callback : callbacks) {
+ MethodMetadata metadata = manipulation.getMethod(callback.getMethodName());
+ if (metadata == null) {
+ dependency.getHandler().debug("A dependency callback " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " does not " +
+ "exist in the implementation class, will try the parent classes");
+ } else {
+ String[] parameters = metadata.getMethodArguments();
+ switch(parameters.length) {
+ case 0 : // Just a notification method.
+ callback.setArgument(parameters);
+ break;
+ case 1 :
+ // Can be the service object, service reference or properties
+ callback.setArgument(parameters);
+ break;
+ case 2 :
+ // Constraints on the second argument, must be a service reference, a dictionary or a map
+ if (!ServiceReference.class.getName().equals(parameters[1])
+ && ! Dictionary.class.getName().equals(parameters[1])
+ && ! Map.class.getName().equals(parameters[1])) {
+ throw new ConfigurationException("The method " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " is not a valid " +
+ "dependency callback - reason: the second argument (" + parameters[1] +
+ ") must be a service reference, a dictionary or a map.");
+ }
+ callback.setArgument(parameters);
+ break;
+ default:
+ // Invalid signature.
+ throw new ConfigurationException("The method " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " is not a valid " +
+ "dependency callback - reason: the signature is invalid");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks whether the constructor parameter injection is suitable. this check verified that the constructor has
+ * enough parameter.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the constructor is not suitable
+ */
+ private static void ensureThatTheConstructorParameterIsCoherent(Dependency dependency,
+ PojoMetadata manipulation) throws
+ ConfigurationException {
+ if (dependency.getConstructorParameterIndex() != -1) {
+ MethodMetadata[] constructors = manipulation.getConstructors();
+ if (constructors == null || constructors.length == 0) {
+ throw new ConfigurationException("The constructor parameter attribute of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " is inconsistent - reason: there is no constructor in" +
+ " the component class (" + dependency.getHandler().getInstanceManager().getClassName() + ")");
+ }
+
+ //TODO Consider only the first constructor. This is a limitation we should think about,
+ // how to determine which constructor to use. Only one constructor should have annotations,
+ // it could be use as hint.
+ MethodMetadata constructor = constructors[0];
+ if (! (constructor.getMethodArguments().length > dependency.getConstructorParameterIndex())) {
+ throw new ConfigurationException("The constructor parameter attribute of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " is inconsistent - reason: the constructor with the " +
+ "signature " + Arrays.toString(constructor.getMethodArguments()) + " has not enough " +
+ "parameters");
+ }
+
+ }
+ }
+
+ /**
+ * Checks that the field used to inject the dependency is in the component class. If the dependency has no field,
+ * this method does nothing.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the field used to inject the given dependency is not in the component class.
+ */
+ private static void ensureThatTheFieldIsInComponentClass(Dependency dependency, PojoMetadata manipulation) throws ConfigurationException {
+ if (dependency.getField() != null) {
+ FieldMetadata field = manipulation.getField(dependency.getField());
+ if (field == null) {
+ throw new ConfigurationException("Incorrect field injection for " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: the field " + dependency.getField() + " is" +
+ " not in the component class (" + dependency.getHandler().getInstanceManager().getClassName()
+ + ")");
+ }
+ }
+ }
+
+ /**
+ * Determines if the dependency is aggregate from the field or constructor parameter used to inject the dependency.
+ * If the dependency just uses methods, this method does nothing. This method also check that dependencies set to
+ * aggregate have a valid injection type.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the type of the field or constructor parameter used to inject the dependency
+ * is not suitable for aggregate dependencies.
+ */
+ private static void deduceAggregationFromTheInjectionPoints(Dependency dependency, PojoMetadata manipulation) throws ConfigurationException {
+ if (dependency.getField() != null) {
+ FieldMetadata field = manipulation.getField(dependency.getField());
+ String type = field.getFieldType();
+ if (type.endsWith("[]")) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.ARRAY);
+ } else if (Collection.class.getName().equals(type) || List.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.LIST);
+ } else if (Set.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.SET);
+ } else if (Vector.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.VECTOR);
+ } else if (dependency.isAggregate()) {
+ // Something wrong. The dependency has a field that is not suitable for aggregate dependencies
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " cannot be an aggregate dependency - reason: the type " + field.getFieldType
+ () + " of the field " + field.getFieldName() + " is not suitable for aggregate " +
+ "dependencies. Compatible types are array, vector, list, set and collection.");
+ }
+ }
+ if (dependency.getConstructorParameterIndex() != -1) {
+ String type = manipulation.getConstructors()[0].getMethodArguments()[dependency
+ .getConstructorParameterIndex()];
+ if (type.endsWith("[]")) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.ARRAY);
+ } else if (Collection.class.getName().equals(type) || List.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.LIST);
+ } else if (Set.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.SET);
+ } else if (Vector.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.VECTOR);
+ } else if (dependency.isAggregate()) {
+ // Something wrong. The dependency has a field that is not suitable for aggregate dependencies
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " cannot be an aggregate dependency - reason: the type " + type
+ + " of the constructor parameter " + dependency.getConstructorParameterIndex() + " is not suitable for aggregate " +
+ "dependencies. Compatible types are array, vector, list, set and collection.");
+ }
+ }
+ //TODO We may not cover some cases such as inconsistency between the constructor and the field. However this
+ // should be very rare.
+
+ }
+
+ /**
+ * Checks that the dependency has at least one injection point.
+ * @param dependency the dependency
+ * @throws ConfigurationException if the dependency has no injection point
+ */
+ private static void ensureThatAtLeastOneInjectionIsSpecified(Dependency dependency) throws ConfigurationException {
+ if (dependency.getField() == null
+ && (dependency.getCallbacks() == null || dependency.getCallbacks().length == 0)
+ && dependency.getConstructorParameterIndex() == -1) {
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " is invalid - reason: no injection specified, at least a field, " +
+ "a method or a constructor parameter index must be set");
+ }
+ }
+
+ /**
+ * Checks that the `from` attribute is used consistently:
+ * <ul>
+ * <li>Rule 1 : it cannot be used on aggregate dependency</li>
+ * <li>Rule 2 : it cannot be used in combination with the `comparator` attribute</li>
+ * <li>Rule 3 : it cannot be used in combination with the `dynamic-priority` binding policy</li>
+ * </ul>
+ *
+ * @param dependency the dependency
+ * @param metadata the dependency metadata
+ * @throws ConfigurationException if the `from` attribute is used inconsistently.
+ */
+ private static void checkTheConsistencyOfTheFromAttribute(Dependency dependency,
+ Element metadata) throws ConfigurationException {
+ // Check if we have a from attribute.
+ if (metadata.getAttribute("from") != null) {
+ final String message = "The `from` attribute is not usable in " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: ";
+ // Rule 1
+ if (dependency.isAggregate()) {
+ throw new ConfigurationException(message + "the dependency is " +
+ "aggregate");
+ }
+ // Rule 2
+ String comparator = metadata.getAttribute("comparator");
+ if (comparator != null) {
+ throw new ConfigurationException(message + "the dependency uses a comparator");
+ }
+ // Rule 3
+ if (dependency.getBindingPolicy() == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ throw new ConfigurationException(message + "the dependency uses the dynamic-priority " +
+ "binding policy");
+ }
+ }
+ }
+
+ /**
+ * Checks that service unavailable actions are consistent.
+ * <ul>
+ * <li>Rule 1: Nullable, Exception, Default-Implementation... can only be used for scalar optional dependency</li>
+ * <li>Rule 2: Only one can be used</li>
+ * <li>Rule 3: Timeout can only be used on optional dependency</li>
+ * </ul>
+ *
+ * @param dependency the dependency
+ * @throws ConfigurationException if the dependency used inconsistent attributes
+ */
+ private static void checkTheServiceUnavailableAction(Dependency dependency,
+ Element metadata) throws ConfigurationException {
+ if (metadata.containsAttribute("nullable") || dependency.getDefaultImplementation() != null || dependency
+ .getException() != null) {
+ // Rule 1:
+ String message = "The `nullable`, `default-implementation` and `exception` attributes are not " +
+ "usable in " + DependencyHandler.getDependencyIdentifier(dependency) + " - reason: ";
+ if (dependency.isAggregate()) {
+ throw new ConfigurationException(message + "the dependency is aggregate");
+ }
+ if (! dependency.isOptional()) {
+ throw new ConfigurationException(message + "the dependency is mandatory");
+ }
+
+ // At this point, we know that the dependency is scalar and optional, and at least one attribute is set
+
+ // Rule 2:
+ message = "Inconsistent use of the `nullable`, `default-implementation` and `exception` attributes are " +
+ "not usable in " + DependencyHandler.getDependencyIdentifier(dependency) + " - reason: ";
+ if (metadata.containsAttribute("nullable") && dependency.getDefaultImplementation() != null) {
+ throw new ConfigurationException(message + "`nullable` and `default-implementation` cannot be " +
+ "combined");
+ }
+ if (metadata.containsAttribute("nullable") && dependency.getException() != null) {
+ throw new ConfigurationException(message + "`nullable` and `exception` cannot be combined");
+ }
+ if (dependency.getDefaultImplementation() != null && dependency.getException() != null) {
+ throw new ConfigurationException(message + "`exception` and `default-implementation` cannot be " +
+ "combined");
+ }
+ }
+
+ // Rule 3:
+ if (dependency.getTimeout() != 0 && ! dependency.isOptional()) {
+ throw new ConfigurationException("The `timeout` attribute is not usable in " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: the dependency is not optional");
+ }
+
+
+
+
+ }
+
+ /**
+ * Tries to determine the service specification to inject in the dependency.
+ * If the specification is already checked by the dependency, just checks the consistency.
+ *
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the specification cannot be deduced, or when the set specification is not
+ * consistent.
+ */
+ private static void deduceTheServiceSpecification(Dependency dependency, PojoMetadata manipulation) throws
+ ConfigurationException {
+
+ // Deduction algorithm
+ String fieldType = null;
+ String callbackType = null;
+ String constructorType = null;
+ // First check the field
+ if (dependency.getField() != null) {
+ fieldType = extractSpecificationFromField(dependency.getField(), manipulation);
+ }
+ if (dependency.getCallbacks() != null && dependency.getCallbacks().length != 0) {
+ callbackType = extractSpecificationFromMethods(dependency, dependency.getCallbacks(), manipulation);
+ }
+ if (dependency.getConstructorParameterIndex() != -1) {
+ constructorType = extractSpecificationFromConstructor(dependency.getConstructorParameterIndex(),
+ manipulation);
+ }
+
+ if (dependency.getSpecification() == null
+ && fieldType == null && callbackType == null && constructorType == null) {
+ throw new ConfigurationException("The deduction of the service specification for " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " has failed - reason: when neither the field, " +
+ "methods and constructor parameter have provided the service specification, " +
+ "the `specification` attribute must be set");
+
+ }
+
+ // The Dependency.setSpecification method check whether the specification coming from the different sources
+ // are consistent.
+ if (fieldType != null) {
+ setSpecification(dependency, fieldType);
+ }
+ if (callbackType != null) {
+ setSpecification(dependency, callbackType);
+ }
+ if (constructorType != null) {
+ setSpecification(dependency, constructorType);
+ }
+ }
+
+ private static String extractSpecificationFromMethods(Dependency dependency, DependencyCallback[] callbacks,
+ PojoMetadata manipulation) throws ConfigurationException {
+ String type = null;
+ for (DependencyCallback callback : callbacks) {
+ MethodMetadata metadata = manipulation.getMethod(callback.getMethodName());
+ if (metadata != null) {
+ String[] parameters = metadata.getMethodArguments();
+ if (parameters.length == 1 || parameters.length == 2) {
+ if (! ServiceReference.class.getName().equals(parameters[0])
+ && ! Dictionary.class.getName().equals(parameters[0])
+ && ! Map.class.getName().equals(parameters[0])) {
+ if (type == null) {
+ type = parameters[0];
+ } else {
+ if (! type.equals(parameters[0])) {
+ throw new ConfigurationException("The callbacks of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " have inconsistent parameters");
+ }
+ }
+ }
+ }
+ }
+ }
+ return type;
+ }
+
+ private static String extractSpecificationFromConstructor(int index, PojoMetadata manipulation) {
+ // We can write the following instructions as everything was previously checked.
+ String type = manipulation.getConstructors()[0].getMethodArguments()[index];
+ if (type.endsWith("[]")) {
+ return type.substring(0, type.length() - 2);
+ }
+ if (AggregateDependencyInjectionType.AGGREGATE_TYPES.contains(type)) {
+ return null; // It's an aggregate
+ }
+ return type;
+ }
+
+ /**
+ * Extracts the service specification from the field.
+ * When this method is called, we know that the field is containing in the component class.
+ * @param field the field
+ * @param manipulation the manipulation metadata
+ * @return the service specification, or {@code null} if is cannot be extracted.
+ */
+ private static String extractSpecificationFromField(String field, PojoMetadata manipulation) {
+ FieldMetadata metadata = manipulation.getField(field);
+ if (metadata.getFieldType().endsWith("[]")) {
+ return metadata.getFieldType().substring(0, metadata.getFieldType().length() - 2);
+ }
+ if (AggregateDependencyInjectionType.AGGREGATE_TYPES.contains(metadata.getFieldType())) {
+ return null; // It's an aggregate
+ }
+ return metadata.getFieldType();
+ }
+
+ /**
+ * Sets the dependency specification. If the dependency has already a specification set,
+ * throw an error if the current specification and the given one are not equal.
+ * @param dep the dependency
+ * @param className the service specification
+ * @throws ConfigurationException if the given specification is not loadable or if the dependency has already a
+ * specification set that is not the given one.
+ */
+ private static void setSpecification(Dependency dep, String className) throws ConfigurationException {
+ if (dep.getSpecification() != null && ! dep.getSpecification().getName().equals(className)) {
+ throw new ConfigurationException("Inconsistent service specification for " + DependencyHandler
+ .getDependencyIdentifier(dep) + " - reason: mismatch between the current specification (" + dep
+ .getSpecification().getName() + ") and the discovered specification (" + className + ")");
+ } else if (dep.getSpecification() == null) {
+ // Set the specification
+ try {
+ dep.setSpecification(dep.getBundleContext().getBundle().loadClass(className));
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Cannot set the service specification of " + DependencyHandler
+ .getDependencyIdentifier(dep) + " - reason: the class " + className + " cannot be loaded from" +
+ " the bundle " + dep.getBundleContext().getBundle().getBundleId(), e);
+ }
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
new file mode 100644
index 0000000..9e95357
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
@@ -0,0 +1,174 @@
+/*
+ * 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.handlers.dependency;
+
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.felix.ipojo.util.DependencyModelListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service Dependency Description.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DependencyDescription {
+ /**
+ * The described dependency.
+ */
+ private final Dependency m_dependency;
+
+ /**
+ * Creates a dependency description.
+ * @param dep the described dependency
+ */
+ public DependencyDescription(Dependency dep) {
+ m_dependency = dep;
+ }
+
+ public boolean isMultiple() { return m_dependency.isAggregate(); }
+
+ public boolean isOptional() { return m_dependency.isOptional(); }
+
+ public String getFilter() { return m_dependency.getFilter(); }
+
+ public String getInterface() { return m_dependency.getSpecification().getName(); }
+
+ public int getState() { return m_dependency.getState(); }
+
+ public String getId() { return m_dependency.getId(); }
+
+ public boolean isProxy() { return m_dependency.isProxy(); }
+
+
+ /**
+ * Gets <code>true</code> if the dependency uses Nullable objects.
+ * @return true if the dependency is optional and supports nullable object.
+ */
+ public boolean supportsNullable() { return m_dependency.supportsNullable(); }
+
+ public String getDefaultImplementation() { return m_dependency.getDefaultImplementation(); }
+
+ public int getPolicy() { return m_dependency.getBindingPolicy(); }
+
+ public String getComparator() { return m_dependency.getComparator(); }
+
+ public boolean isFrozen() { return m_dependency.isFrozen(); }
+
+ /**
+ * Gets the service reference list.
+ * @return the list of matching service reference,
+ * <code>null</code> if no service reference.
+ */
+ public List<ServiceReference> getServiceReferences() { return m_dependency.getServiceReferencesAsList(); }
+
+ /**
+ * Gets the service reference if only one service reference is used.
+ * @return the ServiceReference (only if the cardinality could be 1),
+ * or <code>null</code> if no service reference.
+ */
+ public ServiceReference getServiceReference() {
+ List list = getServiceReferences();
+ if (list == null) {
+ return null;
+ } else {
+ return (ServiceReference) list.get(0);
+ }
+ }
+
+ /**
+ * Gets the used service set.
+ * @return the list [service reference] containing the used services,
+ * <code>null</code> if no providers are used
+ */
+ public List<ServiceReference> getUsedServices() { return m_dependency.getUsedServiceReferences(); }
+
+ /**
+ * Sets the dependency comparator.
+ * The reference set will be sort at the next usage.
+ * @param cmp the comparator
+ */
+ public void setComparator(Comparator cmp) {
+ m_dependency.setComparator(cmp);
+ }
+
+ /**
+ * Sets the dependency filter.
+ * @param filter the new LDAP filter
+ */
+ public void setFilter(Filter filter) {
+ m_dependency.setFilter(filter);
+ }
+
+ /**
+ * Sets the dependency cardinality.
+ * @param isAgg if <code>true</code> sets the dependency to aggregate,
+ * if <code>false</code> sets the dependency to scalar.
+ */
+ public void setAggregate(boolean isAgg) {
+ m_dependency.setAggregate(isAgg);
+ }
+
+ /**
+ * Sets the dependency optionality.
+ * @param isOpt if <code>true</code> sets the dependency to optional,
+ * if <code>false</code> sets the dependency to mandatory.
+ */
+ public void setOptional(boolean isOpt) {
+ m_dependency.setOptionality(isOpt);
+ }
+
+ /**
+ * Gets the required service specification name.
+ * @return the required service specification class name.
+ */
+ public String getSpecification() {
+ return m_dependency.getSpecification().getName();
+ }
+
+ /**
+ * Gets the described dependency.
+ * @return the dependency.
+ */
+ public Dependency getDependency() {
+ return m_dependency;
+ }
+
+ /**
+ * Add the given listener to the dependency model's list of listeners.
+ *
+ * @param listener the {@code DependencyModelListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(DependencyModelListener listener) {
+ m_dependency.addListener(listener);
+ }
+
+ /**
+ * Remove the given listener from the dependency model's list of listeners.
+ *
+ * @param listener the {@code DependencyModelListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ * @throws java.util.NoSuchElementException if {@code listener} wasn't present in the dependency model's list of listeners
+ */
+ public void removeListener(DependencyModelListener listener) {
+ m_dependency.removeListener(listener);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
new file mode 100644
index 0000000..6037f11
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -0,0 +1,558 @@
+/*
+ * 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.handlers.dependency;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+import java.util.*;
+
+/**
+ * The dependency handler manages a list of service dependencies.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DependencyHandler extends PrimitiveHandler implements DependencyStateListener {
+
+ /**
+ * Proxy settings property.
+ */
+ public static final String PROXY_SETTINGS_PROPERTY = "ipojo.proxy";
+ /**
+ * Proxy type property.
+ */
+ public static final String PROXY_TYPE_PROPERTY = "ipojo.proxy.type";
+ /**
+ * Proxy type value: smart.
+ */
+ public static final String SMART_PROXY = "smart";
+ /**
+ * Proxy type value: dynamic-proxy.
+ */
+ public static final String DYNAMIC_PROXY = "dynamic-proxy";
+ /**
+ * Proxy settings value: enabled.
+ */
+ public static final String PROXY_ENABLED = "enabled";
+ /**
+ * Proxy settings value: disabled.
+ */
+ public static final String PROXY_DISABLED = "disabled";
+ /**
+ * List of dependencies of the component.
+ */
+ private final List<Dependency> m_dependencies = new ArrayList<Dependency>();
+ /**
+ * Is the handler started.
+ */
+ private boolean m_started;
+ /**
+ * The handler description.
+ */
+ private DependencyHandlerDescription m_description;
+ /**
+ * The instance configuration context source, updated once reconfiguration.
+ */
+ private InstanceConfigurationSource m_instanceConfigurationSource;
+
+ /**
+ * Builds a description of this dependency to help the user to identify it. IT's not related to the Dependency
+ * Description, it's just a string containing dependency information to spot it easily in the code.
+ *
+ * @param dep the dependency
+ * @return the identifier containing (if defined) the id, the specification, the field and the callback.
+ * @since 1.10.1
+ */
+ public static String getDependencyIdentifier(Dependency dep) {
+ StringBuilder identifier = new StringBuilder("{");
+ if (dep.getId() != null) {
+ identifier.append("id=").append(dep.getId());
+ }
+ if (dep.getField() != null) {
+ if (identifier.length() > 1) {
+ identifier.append(", ");
+ }
+ identifier.append("field=").append(dep.getField());
+ }
+ if (dep.getCallbacks() != null && dep.getCallbacks().length > 0) {
+ if (identifier.length() > 1) {
+ identifier.append(", ");
+ }
+ identifier.append("method=").append(dep.getCallbacks()[0].getMethodName());
+ }
+ if (dep.getSpecification() != null) {
+ if (identifier.length() > 1) {
+ identifier.append(", ");
+ }
+ identifier.append("specification=").append(dep.getSpecification().getName());
+ }
+ identifier.append("}");
+ return identifier.toString();
+ }
+
+ /**
+ * Get the list of managed dependency.
+ *
+ * @return the dependency list
+ */
+ public Dependency[] getDependencies() {
+ return m_dependencies.toArray(new Dependency[m_dependencies.size()]);
+ }
+
+ /**
+ * Validate method. This method is invoked by an AbstractServiceDependency when this dependency becomes RESOLVED.
+ *
+ * @param dep : the dependency becoming RESOLVED.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#validate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void validate(DependencyModel dep) {
+ checkContext();
+ }
+
+ /**
+ * Invalidate method. This method is invoked by an AbstractServiceDependency when this dependency becomes UNRESOLVED or BROKEN.
+ *
+ * @param dep : the dependency becoming UNRESOLVED or BROKEN.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#invalidate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void invalidate(DependencyModel dep) {
+ setValidity(false);
+ }
+
+ /**
+ * Check the validity of the dependencies.
+ */
+ protected void checkContext() {
+ if (!m_started) {
+ return;
+ }
+ synchronized (m_dependencies) {
+ // Store the initial state
+ boolean initialState = getValidity();
+
+ boolean valid = true;
+ for (Dependency dep : m_dependencies) {
+ if (dep.getState() != Dependency.RESOLVED) {
+ valid = false;
+ break;
+ }
+ }
+
+ // Check the component dependencies
+ if (valid) {
+ // The dependencies are valid
+ if (!initialState) {
+ // There is a state change
+ setValidity(true);
+ }
+ // Else do nothing, the component state stay VALID
+ } else {
+ // The dependencies are not valid
+ if (initialState) {
+ // There is a state change
+ setValidity(false);
+ }
+ // Else do nothing, the component state stay UNRESOLVED
+ }
+
+ }
+ }
+
+ /**
+ * Configure the handler.
+ *
+ * @param componentMetadata : the component type metadata
+ * @param configuration : the instance configuration
+ * @throws ConfigurationException : one dependency metadata is not correct.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element componentMetadata, Dictionary configuration) throws ConfigurationException {
+ PojoMetadata manipulation = getFactory().getPojoMetadata();
+ boolean atLeastOneField = false;
+
+ // Create the dependency according to the component metadata
+ Element[] deps = componentMetadata.getElements("Requires");
+
+ // Get instance filters.
+ Dictionary filtersConfiguration = getRequiresFilters(configuration.get("requires.filters"));
+ Dictionary fromConfiguration = (Dictionary) configuration.get("requires.from");
+
+ for (int i = 0; deps != null && i < deps.length; i++) {
+ // Create the dependency metadata
+ final Element dependencyElement = deps[i];
+
+ String field = dependencyElement.getAttribute("field");
+ String serviceSpecification = getServiceSpecificationAttribute(dependencyElement);
+ String opt = dependencyElement.getAttribute("optional");
+ boolean optional = opt != null && opt.equalsIgnoreCase("true");
+ String defaultImpl = dependencyElement.getAttribute("default-implementation");
+ String exception = dependencyElement.getAttribute("exception");
+ String to = dependencyElement.getAttribute("timeout");
+ int timeout = 0;
+ if (to != null) {
+ timeout = Integer.parseInt(to);
+ }
+
+ String agg = dependencyElement.getAttribute("aggregate");
+ boolean aggregate = agg != null && agg.equalsIgnoreCase("true");
+
+ String identity = dependencyElement.getAttribute("id");
+
+ String nul = dependencyElement.getAttribute("nullable");
+ boolean nullable = nul == null || nul.equalsIgnoreCase("true");
+
+ boolean isProxy = isProxy(dependencyElement);
+
+ BundleContext context = getFacetedBundleContext(dependencyElement);
+
+ String filter = computeFilter(dependencyElement, filtersConfiguration, fromConfiguration, aggregate, identity);
+ Filter fil = createAndCheckFilter(filter);
+
+ Class spec = null;
+ if (serviceSpecification != null) {
+ spec = DependencyMetadataHelper.loadSpecification(serviceSpecification, getInstanceManager().getContext());
+ }
+
+ int policy = DependencyMetadataHelper.getPolicy(dependencyElement);
+ Comparator cmp = DependencyMetadataHelper.getComparator(dependencyElement, getInstanceManager().getGlobalContext());
+
+ Dependency dep = new Dependency(this, field, spec, fil, optional, aggregate, nullable, isProxy, identity,
+ context, policy, cmp, defaultImpl, exception);
+ dep.setTimeout(timeout);
+
+ // Look for dependency callback :
+ addCallbacksToDependency(dependencyElement, dep);
+
+ // Add the constructor parameter if needed
+ String paramIndex = dependencyElement.getAttribute("constructor-parameter");
+ if (paramIndex != null) {
+ int index = Integer.parseInt(paramIndex);
+ dep.addConstructorInjection(index);
+ }
+
+ // Check the dependency, throws an exception on error.
+ DependencyConfigurationChecker.ensure(dep, dependencyElement, manipulation);
+ m_dependencies.add(dep);
+ if (dep.getField() != null) {
+ getInstanceManager().register(manipulation.getField(dep.getField()), dep);
+ atLeastOneField = true;
+ }
+
+ }
+
+ if (atLeastOneField) { // Does register only if we have fields
+ MethodMetadata[] methods = manipulation.getMethods();
+ for (MethodMetadata method : methods) {
+ for (Dependency dep : m_dependencies) {
+ getInstanceManager().register(method, dep);
+ }
+ }
+
+ // Also track the inner class methods
+ for (String inner : manipulation.getInnerClasses()) {
+ MethodMetadata[] meths = manipulation.getMethodsFromInnerClass(inner);
+ if (meths != null) {
+ for (MethodMetadata method : meths) {
+ for (Dependency dep : m_dependencies) {
+ getInstanceManager().register(method, inner, dep);
+ }
+ }
+ }
+ }
+ }
+
+ m_description = new DependencyHandlerDescription(this, getDependencies()); // Initialize the description.
+
+ manageContextSources(configuration);
+ }
+
+ /**
+ * Add internal context source to all dependencies.
+ *
+ * @param configuration the instance configuration to creates the instance configuration source
+ */
+ private void manageContextSources(Dictionary<String, Object> configuration) {
+ m_instanceConfigurationSource = new InstanceConfigurationSource(configuration);
+ SystemPropertiesSource systemPropertiesSource = new SystemPropertiesSource();
+
+ for (Dependency dependency : m_dependencies) {
+ if (dependency.getFilter() != null) {
+ dependency.getContextSourceManager().addContextSource(m_instanceConfigurationSource);
+ dependency.getContextSourceManager().addContextSource(systemPropertiesSource);
+
+ for (Handler handler : getInstanceManager().getRegisteredHandlers()) {
+ if (handler instanceof ContextSource) {
+ dependency.getContextSourceManager().addContextSource((ContextSource) handler);
+ }
+ }
+ }
+ }
+ }
+
+ private String computeFilter(Element dependencyElement, Dictionary filtersConfiguration, Dictionary fromConfiguration, boolean aggregate, String identity) {
+ String filter = dependencyElement.getAttribute("filter");
+ // Get instance filter if available
+ if (filtersConfiguration != null && identity != null && filtersConfiguration.get(identity) != null) {
+ filter = (String) filtersConfiguration.get(identity);
+ }
+
+ // Compute the 'from' attribute
+ filter = updateFilterIfFromIsEnabled(fromConfiguration, dependencyElement, filter, aggregate, identity);
+ return filter;
+ }
+
+ private String updateFilterIfFromIsEnabled(Dictionary fromConfiguration, Element dependencyElement, String filter, boolean aggregate, String identity) {
+ String from = dependencyElement.getAttribute("from");
+ if (fromConfiguration != null && identity != null && fromConfiguration.get(identity) != null) {
+ from = (String) fromConfiguration.get(identity);
+ }
+ if (from != null) {
+ String fromFilter = "(|(instance.name=" + from + ")(service.pid=" + from + "))";
+ if (aggregate) {
+ warn("The 'from' attribute is incompatible with aggregate requirements: only one provider will match : " + fromFilter);
+ }
+ if (filter != null) {
+ filter = "(&" + fromFilter + filter + ")"; // Append the two filters
+ } else {
+ filter = fromFilter;
+ }
+ }
+ return filter;
+ }
+
+ private boolean isProxy(Element dependencyElement) {
+ boolean isProxy = true;
+ String setting = getProxySetting();
+
+ if (setting == null || PROXY_ENABLED.equals(setting)) { // If not set => Enabled
+ isProxy = true;
+ } else if (PROXY_DISABLED.equals(setting)) {
+ isProxy = false;
+ }
+
+ String proxy = dependencyElement.getAttribute("proxy");
+ // If proxy == null, use default value
+ if (proxy != null) {
+ if (proxy.equals("false")) {
+ isProxy = false;
+ } else if (proxy.equals("true")) {
+ if (!isProxy) { // The configuration overrides the system setting
+ warn("The configuration of a service dependency overrides the proxy mode");
+ }
+ isProxy = true;
+ }
+ }
+ return isProxy;
+ }
+
+ private String getProxySetting() {
+ // Detect proxy default value.
+ String setting = getInstanceManager().getContext().getProperty(PROXY_SETTINGS_PROPERTY);
+
+ // Felix also includes system properties in the bundle context property, however it is not the case of the
+ // other frameworks, so if it's null we should call System.getProperty.
+
+ if (setting == null) {
+ setting = System.getProperty(PROXY_SETTINGS_PROPERTY);
+ }
+ return setting;
+ }
+
+ private void addCallbacksToDependency(Element dependencyElement, Dependency dep) throws ConfigurationException {
+ Element[] cbs = dependencyElement.getElements("Callback");
+ for (int j = 0; cbs != null && j < cbs.length; j++) {
+ if (!cbs[j].containsAttribute("method") || !cbs[j].containsAttribute("type")) {
+ throw new ConfigurationException("Requirement Callback : a dependency callback must contain a method " +
+ "and a type (bind or unbind) attribute");
+ }
+ String method = cbs[j].getAttribute("method");
+ String type = cbs[j].getAttribute("type");
+
+ int methodType = DependencyCallback.UNBIND;
+ if ("bind".equalsIgnoreCase(type)) {
+ methodType = DependencyCallback.BIND;
+ } else if ("modified".equalsIgnoreCase(type)) {
+ methodType = DependencyCallback.MODIFIED;
+ }
+
+ dep.addDependencyCallback(createDependencyHandler(dep, method, methodType));
+ }
+ }
+
+ protected DependencyCallback createDependencyHandler(final Dependency dep, final String method, final int type) {
+ return new DependencyCallback(dep, method, type);
+ }
+
+ private Filter createAndCheckFilter(String filter) throws ConfigurationException {
+ Filter fil = null;
+ if (filter != null) {
+ try {
+ fil = getInstanceManager().getContext().createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("A requirement filter is invalid : " + filter, e);
+ }
+ }
+ return fil;
+ }
+
+ private BundleContext getFacetedBundleContext(Element dep) {
+ String scope = dep.getAttribute("scope");
+ BundleContext context = getInstanceManager().getContext(); // Get the default bundle context.
+ if (scope != null) {
+ // If we are not in a composite, the policy is set to global.
+ if (scope.equalsIgnoreCase("global") || ((((IPojoContext) getInstanceManager().getContext()).getServiceContext()) == null)) {
+ context =
+ new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(),
+ PolicyServiceContext.GLOBAL);
+ } else if (scope.equalsIgnoreCase("composite")) {
+ context =
+ new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(),
+ PolicyServiceContext.LOCAL);
+ } else if (scope.equalsIgnoreCase("composite+global")) {
+ context =
+ new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(),
+ PolicyServiceContext.LOCAL_AND_GLOBAL);
+ }
+ }
+ return context;
+ }
+
+ private String getServiceSpecificationAttribute(Element dep) {
+ String serviceSpecification = dep.getAttribute("interface");
+ // the 'interface' attribute is deprecated
+ if (serviceSpecification != null) {
+ warn("The 'interface' attribute is deprecated, use the 'specification' attribute instead");
+ } else {
+ serviceSpecification = dep.getAttribute("specification");
+ }
+ return serviceSpecification;
+ }
+
+ /**
+ * Gets the requires filter configuration from the given object.
+ * The given object must come from the instance configuration.
+ * This method was made to fix FELIX-2688. It supports filter configuration using
+ * an array:
+ * <code>{"myFirstDep", "(property1=value1)", "mySecondDep", "(property2=value2)"});</code>
+ *
+ * @param requiresFiltersValue the value contained in the instance
+ * configuration.
+ * @return the dictionary. If the object in already a dictionary, just returns it,
+ * if it's an array, builds the dictionary.
+ * @throws ConfigurationException the dictionary cannot be built
+ */
+ private Dictionary getRequiresFilters(Object requiresFiltersValue)
+ throws ConfigurationException {
+ if (requiresFiltersValue != null
+ && requiresFiltersValue.getClass().isArray()) {
+ String[] filtersArray = (String[]) requiresFiltersValue;
+ if (filtersArray.length % 2 != 0) {
+ throw new ConfigurationException(
+ "A requirement filter is invalid : "
+ + requiresFiltersValue);
+ }
+ Dictionary<String, Object> requiresFilters = new Hashtable<String, Object>();
+ for (int i = 0; i < filtersArray.length; i += 2) {
+ requiresFilters.put(filtersArray[i], filtersArray[i + 1]);
+ }
+ return requiresFilters;
+ }
+
+ return (Dictionary) requiresFiltersValue;
+ }
+
+ /**
+ * Handler start method.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Start the dependencies
+ for (Dependency dep : m_dependencies) {
+ dep.start();
+ }
+ // Check the state
+ m_started = true;
+ setValidity(false);
+ checkContext();
+ }
+
+ /**
+ * Handler stop method.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ m_started = false;
+ for (Dependency dep : m_dependencies) {
+ dep.stop();
+ }
+ }
+
+ /**
+ * Handler createInstance method. This method is override to allow delayed callback invocation.
+ *
+ * @param instance : the created object
+ * @see org.apache.felix.ipojo.PrimitiveHandler#onCreation(Object)
+ */
+ public void onCreation(Object instance) {
+ for (Dependency dep : m_dependencies) {
+ dep.onObjectCreation(instance);
+ }
+ }
+
+ /**
+ * Get the dependency handler description.
+ *
+ * @return the dependency handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /**
+ * The instance is reconfigured.
+ *
+ * @param configuration the new instance configuration.
+ */
+ @Override
+ public void reconfigure(Dictionary configuration) {
+ m_instanceConfigurationSource.reconfigure(configuration);
+ }
+
+ @Override
+ public void stateChanged(int state) {
+ if (state == ComponentInstance.DISPOSED) {
+ // Cleanup all dependencies
+ for (Dependency dep : m_dependencies) {
+ dep.cleanup();
+ }
+ }
+ super.stateChanged(state);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
new file mode 100644
index 0000000..74c6e09
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
@@ -0,0 +1,208 @@
+/*
+ * 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.handlers.dependency;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.dependency.impl.ServiceReferenceManager;
+import org.apache.felix.ipojo.dependency.interceptors.ServiceTrackingInterceptor;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Dependency Handler Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DependencyHandlerDescription extends HandlerDescription {
+
+ /**
+ * Dependencies managed by the dependency handler.
+ */
+ private DependencyDescription[] m_dependencies = new DependencyDescription[0];
+
+ /**
+ * Creates the Dependency Handler description.
+ * @param handler the Dependency Handler.
+ * @param deps the Dependencies
+ */
+ public DependencyHandlerDescription(DependencyHandler handler, Dependency[] deps) {
+ super(handler);
+ m_dependencies = new DependencyDescription[deps.length];
+ for (int i = 0; i < m_dependencies.length; i++) {
+ m_dependencies[i] = new DependencyDescription(deps[i]);
+ }
+ }
+
+ /**
+ * Get dependencies description.
+ * @return the dependencies list.
+ */
+ public DependencyDescription[] getDependencies() {
+ return m_dependencies;
+ }
+
+ /**
+ * Builds the Dependency Handler description.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element deps = super.getHandlerInfo();
+ for (DependencyDescription dependency : m_dependencies) {
+ String state = "resolved";
+ if (dependency.getState() == DependencyModel.UNRESOLVED) {
+ state = "unresolved";
+ }
+ if (dependency.getState() == DependencyModel.BROKEN) {
+ state = "broken";
+ }
+ Element dep = new Element("Requires", "");
+ dep.addAttribute(new Attribute("Specification", dependency.getInterface()));
+ dep.addAttribute(new Attribute("Id", dependency.getId()));
+
+ if (dependency.getFilter() != null) {
+ dep.addAttribute(new Attribute("Filter", dependency.getFilter()));
+ }
+
+ if (dependency.isOptional()) {
+ dep.addAttribute(new Attribute("Optional", "true"));
+ if (dependency.supportsNullable()) {
+ dep.addAttribute(new Attribute("Nullable", "true"));
+ }
+ if (dependency.getDefaultImplementation() != null) {
+ dep.addAttribute(new Attribute("Default-Implementation", dependency.getDefaultImplementation()));
+ }
+ } else {
+ dep.addAttribute(new Attribute("Optional", "false"));
+ }
+
+ if (dependency.isMultiple()) {
+ dep.addAttribute(new Attribute("Aggregate", "true"));
+ } else {
+ dep.addAttribute(new Attribute("Aggregate", "false"));
+ }
+
+ if (dependency.isProxy()) {
+ dep.addAttribute(new Attribute("Proxy", "true"));
+ } else {
+ dep.addAttribute(new Attribute("Proxy", "false"));
+ }
+
+ String policy = "dynamic";
+ if (dependency.getPolicy() == DependencyModel.STATIC_BINDING_POLICY) {
+ policy = "static";
+ } else if (dependency.getPolicy() == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ policy = "dynamic-priority";
+ }
+ dep.addAttribute(new Attribute("Binding-Policy", policy));
+
+ if (dependency.getComparator() != null) {
+ dep.addAttribute(new Attribute("Comparator", dependency.getComparator()));
+ }
+
+ dep.addAttribute(new Attribute("State", state));
+ List<ServiceReference> set = dependency.getUsedServices();
+ if (set != null) {
+ for (ServiceReference ref : set) {
+ Element use = new Element("Uses", "");
+ computeServiceReferenceDescription(ref, use);
+ dep.addElement(use);
+ }
+ }
+
+ set = dependency.getServiceReferences();
+ if (set != null) {
+ for (ServiceReference ref : set) {
+ Element use = new Element("Selected", "");
+ computeServiceReferenceDescription(ref, use);
+ dep.addElement(use);
+ }
+ }
+
+ final ServiceReferenceManager serviceReferenceManager = dependency.getDependency()
+ .getServiceReferenceManager();
+ if (serviceReferenceManager == null) {
+ // Exit here, cannot compute anything else.
+ deps.addElement(dep);
+ continue;
+ }
+
+ set = serviceReferenceManager.getMatchingServices();
+ if (set != null) {
+ for (ServiceReference ref : set) {
+ Element use = new Element("Matches", "");
+ computeServiceReferenceDescription(ref, use);
+ dep.addElement(use);
+ }
+ }
+
+ // Add interceptors to the description
+ List<ServiceReference> interceptors = serviceReferenceManager.getTrackingInterceptorReferences();
+ for (ServiceReference ref : interceptors) {
+ Element itcp = new Element("ServiceTrackingInterceptor", "");
+ computeInterceptorDescription(ref, itcp);
+ dep.addElement(itcp);
+ }
+
+ ServiceReference ref = serviceReferenceManager.getRankingInterceptorReference();
+ if (ref != null) {
+ Element itcp = new Element("ServiceRankingInterceptor", "");
+ computeInterceptorDescription(ref, itcp);
+ dep.addElement(itcp);
+ }
+
+ interceptors = serviceReferenceManager.getBindingInterceptorReferences();
+ for (ServiceReference rf : interceptors) {
+ Element itcp = new Element("ServiceBindingInterceptor", "");
+ computeInterceptorDescription(rf, itcp);
+ dep.addElement(itcp);
+ }
+
+ deps.addElement(dep);
+ }
+ return deps;
+ }
+
+ private void computeServiceReferenceDescription(ServiceReference ref, Element use) {
+ use.addAttribute(new Attribute(Constants.SERVICE_ID, ref.getProperty(Constants.SERVICE_ID).toString()));
+ String instance = (String) ref.getProperty(Factory.INSTANCE_NAME_PROPERTY);
+ if (instance != null) {
+ use.addAttribute(new Attribute(Factory.INSTANCE_NAME_PROPERTY, instance));
+ }
+ }
+
+ private void computeInterceptorDescription(ServiceReference ref, Element itcp) {
+ itcp.addAttribute(new Attribute(Constants.SERVICE_ID, ref.getProperty(Constants.SERVICE_ID).toString()));
+ itcp.addAttribute(new Attribute("bundle.id", Long.toString(ref.getBundle().getBundleId())));
+ String instance = (String) ref.getProperty(Factory.INSTANCE_NAME_PROPERTY);
+ if (instance != null) {
+ itcp.addAttribute(new Attribute(Factory.INSTANCE_NAME_PROPERTY, instance));
+ }
+ itcp.addAttribute(new Attribute("target", ref.getProperty(ServiceTrackingInterceptor.TARGET_PROPERTY)
+ .toString()));
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
new file mode 100644
index 0000000..4d9ddd7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
@@ -0,0 +1,94 @@
+/*
+ * 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.handlers.dependency;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * Default nullable object.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class NullableObject implements InvocationHandler {
+
+ /**
+ * Default boolean value.
+ */
+ private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
+
+ /**
+ * Default byte value.
+ */
+ private static final Byte DEFAULT_BYTE = new Byte((byte) 0);
+
+ /**
+ * Default short value.
+ */
+ private static final Short DEFAULT_SHORT = new Short((short) 0);
+
+ /**
+ * Default integer value.
+ */
+ private static final Integer DEFAULT_INT = new Integer(0);
+
+ /**
+ * Default long value.
+ */
+ private static final Long DEFAULT_LONG = new Long(0);
+
+ /**
+ * Default float value.
+ */
+ private static final Float DEFAULT_FLOAT = new Float(0.0f);
+
+ /**
+ * Default double value.
+ */
+ private static final Double DEFAULT_DOUBLE = new Double(0.0);
+
+ /**
+ * Invokes a method on this null object. The method will return a default
+ * value without doing anything.
+ * @param proxy : proxy object
+ * @param method : invoked method
+ * @param args : arguments.
+ * @return the returned value.
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ Class returnType = method.getReturnType();
+ if (Boolean.TYPE.equals(returnType)) {
+ return DEFAULT_BOOLEAN;
+ } else if (Byte.TYPE.equals(returnType)) {
+ return DEFAULT_BYTE;
+ } else if (Short.TYPE.equals(returnType)) {
+ return DEFAULT_SHORT;
+ } else if (Integer.TYPE.equals(returnType)) {
+ return DEFAULT_INT;
+ } else if (Long.TYPE.equals(returnType)) {
+ return DEFAULT_LONG;
+ } else if (Float.TYPE.equals(returnType)) {
+ return DEFAULT_FLOAT;
+ } else if (Double.TYPE.equals(returnType)) {
+ return DEFAULT_DOUBLE;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
new file mode 100644
index 0000000..345afee
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
@@ -0,0 +1,213 @@
+/*
+ * 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.handlers.dependency;
+
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Generates proxy class delegating operation invocations thanks to a
+ * a dependency.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProxyGenerator implements Opcodes {
+
+ /**
+ * The dependency name.
+ */
+ private static final String DEPENDENCY = "m_dependency";
+
+ /**
+ * The dependency descriptor.
+ */
+ private static final String DEPENDENCY_DESC = Type.getDescriptor(Dependency.class);
+
+ /**
+ * Dependency internal class name.
+ */
+ private static final String DEPENDENCY_INTERNAL_NAME = "org/apache/felix/ipojo/handlers/dependency/Dependency";
+
+ /**
+ * Gets the internal names of the given class objects.
+ * @param classes the classes
+ * @return the array containing internal names of the given class array.
+ */
+ private static String[] getInternalClassNames(Class[] classes) {
+ final String[] names = new String[classes.length];
+ for (int i = 0; i < names.length; i++) {
+ names[i] = Type.getInternalName(classes[i]);
+ }
+ return names;
+ }
+
+ /**
+ * Generates a proxy class.
+ * @param spec the proxied service specification
+ * @return the byte[] for the generated proxy class.
+ */
+ public static byte[] dumpProxy(Class spec) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ String internalClassName = Type.getInternalName(spec); // Specification class internal name.
+ String[] itfs = new String[0];
+ String parent = "java/lang/Object";
+ if (spec.isInterface()) {
+ itfs = new String[] {internalClassName}; // Implemented interface.
+ } else {
+ parent = internalClassName;
+ }
+ String className = internalClassName + "$$Proxy"; // Unique name.
+
+ // Turn around the VM changes (FELIX-2716) about java.* classes.
+ if (className.startsWith("java/")) {
+ className = "$" + className;
+ }
+
+ Method[] methods = spec.getMethods(); // Method to delegate
+
+ cw.visit(Opcodes.V1_3, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, className, null, parent, itfs);
+ addDependencyField(cw);
+
+ // We try to call super() on the parent, however this should not be used as proxing does work only for interface.
+ generateConstructor(cw, className, parent);
+
+ // For each method, create the delegator code.
+ for (int i = 0; i < methods.length; i++) {
+ if ((methods[i].getModifiers() & (Modifier.STATIC | Modifier.FINAL)) == 0) {
+ generateDelegator(cw, methods[i], className, internalClassName);
+ }
+ }
+
+ cw.visitEnd();
+
+ return cw.toByteArray();
+
+ }
+
+ /**
+ * Generates a delegated method.
+ * @param cw the class writer
+ * @param method the method object to delegate
+ * @param className the generated class name
+ * @param itfName the internal specification class name
+ */
+ private static void generateDelegator(ClassWriter cw, Method method,
+ String className, String itfName) {
+ String methodName = method.getName();
+ String desc = Type.getMethodDescriptor(method);
+ String[] exceptions = getInternalClassNames(method.getExceptionTypes());
+ int modifiers = method.getModifiers()
+ & ~(Modifier.ABSTRACT | Modifier.NATIVE | Modifier.SYNCHRONIZED);
+ Type[] types = Type.getArgumentTypes(method);
+
+ int freeRoom = 1;
+ for (int t = 0; t < types.length; t++) {
+ freeRoom = freeRoom + types[t].getSize();
+ }
+
+ MethodVisitor mv = cw.visitMethod(modifiers, methodName, desc, null,
+ exceptions);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // The dependency is on the stack.
+ mv.visitMethodInsn(INVOKEVIRTUAL, DEPENDENCY_INTERNAL_NAME, "getService", // Call getService
+ "()Ljava/lang/Object;"); // The service object is on the stack.
+ int varSvc = freeRoom;
+ freeRoom = freeRoom + 1; // Object Reference.
+ mv.visitVarInsn(ASTORE, varSvc); // Store the service object.
+
+ Label notNull = new Label();
+ Label isNull = new Label();
+ mv.visitVarInsn(ALOAD, varSvc); // Load the service
+ mv.visitJumpInsn(IFNONNULL, notNull); // If not null go to not null
+ // Null branch - throw the exception
+ mv.visitLabel(isNull);
+ mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn("No service available");
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ // End of the null branch
+
+ // Not null, go one the execution
+ mv.visitLabel(notNull);
+
+ // Invoke the method on the service object.
+ mv.visitVarInsn(ALOAD, varSvc);
+ // Push argument on the stack.
+ int i = 1; // Arguments. (non static method)
+ for (int t = 0; t < types.length; t++) {
+ mv.visitVarInsn(types[t].getOpcode(ILOAD), i);
+ i = i + types[t].getSize();
+ }
+ // Invocation
+ mv.visitMethodInsn(INVOKEINTERFACE, itfName, methodName, desc);
+
+ // Return the result
+ Type returnType = Type.getReturnType(desc);
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+ } else {
+ mv.visitInsn(RETURN);
+ }
+
+ // End of the method.
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generates the constructors. The constructor receives a dependency
+ * and set the {@link ProxyGenerator#DEPENDENCY} field.
+ * @param cw the class writer
+ * @param className the generated class name.
+ */
+ private static void generateConstructor(ClassWriter cw, String className, String parent) {
+ MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", '(' + DEPENDENCY_DESC + ")V", null, null);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0); // Load this
+ mv.visitInsn(DUP); // Dup
+ mv.visitMethodInsn(INVOKESPECIAL, parent, "<init>", "()V"); // Call super
+ mv.visitVarInsn(ALOAD, 1); // Load the argument
+ mv.visitFieldInsn(PUTFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // Assign the dependency field
+ mv.visitInsn(RETURN); // Return void
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Adds the dependency field {@link ProxyGenerator#DEPENDENCY}.
+ * @param cw the class writer
+ */
+ private static void addDependencyField(ClassWriter cw) {
+ cw.visitField(Opcodes.ACC_FINAL, DEPENDENCY, DEPENDENCY_DESC, null, null);
+ cw.visitEnd();
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceList.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceList.java
new file mode 100644
index 0000000..177c882
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceList.java
@@ -0,0 +1,456 @@
+/*
+ * 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.handlers.dependency;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Maintains a list of service object.
+ * This collection wrap the dependency to be accessible from a
+ * {@link java.util.Collection} or a {@link java.util.List}, that can be passed to helper objects (Collaborators).
+ * <p/>
+ * The {@link Collection#iterator()} method returns an {@link Iterator} iterating
+ * on a cached copy of available service objects. In the case that there are no
+ * available services, the policies act as follows:
+ * <ul>
+ * <li>'null' returns a null iterator</li>
+ * <li>'nullable' and default-implementation returns an iterator iterating on one object (the
+ * nullable or default-implementation object</li>
+ * <li>'empty' returns an empty iterator.</li>
+ * </ul>
+ * Because of FELIX-4717, this class does not implement Set.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceList implements List {
+
+ /**
+ * The wrapped dependency.
+ */
+ private Dependency m_dependency;
+
+ /**
+ * Creates a Service Collection.
+ *
+ * @param dep the wrapped dependency
+ */
+ public ServiceList(Dependency dep) {
+ m_dependency = dep;
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param o an object
+ * @return N/A
+ * @see java.util.Collection#add(java.lang.Object)
+ */
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c an object
+ * @return N/A
+ * @see java.util.Collection#addAll(java.util.Collection)
+ */
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index an index
+ * @param obj an object
+ * @see java.util.List#add(int, java.lang.Object)
+ */
+ public void add(int index, Object obj) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index an index
+ * @param c an object
+ * @return N/A
+ * @see java.util.List#addAll(int, java.util.Collection)
+ */
+ public boolean addAll(int index, Collection c) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @see java.util.Collection#clear()
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Checks if the wrapped dependency has always access to the
+ * given service object.The method allows knowing if the provider returning the
+ * service object has left.
+ *
+ * @param o the service object
+ * @return <code>true</code> if the object is still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean contains(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.contains(o);
+ }
+
+ /**
+ * Checks if the wrapped dependencies has always access to the
+ * given service objects.The method allows knowing if providers returning the
+ * service objects have left.
+ *
+ * @param c the set of service object
+ * @return <code>true</code> if the objects are still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean containsAll(Collection c) {
+ List list = (List) m_dependency.getService();
+ return list.containsAll(c);
+ }
+
+ /**
+ * Checks if at least one provider matching with the dependency
+ * is available.
+ *
+ * @return <code>true</code> if one provider or more satisfying the
+ * dependency are available. Otherwise, returns <code>false</code>
+ * @see java.util.Collection#isEmpty()
+ */
+ public boolean isEmpty() {
+ return m_dependency.getSize() == 0;
+ }
+
+ /**
+ * Gets an iterator on the current list of available service objects.
+ * The returned iterator iterates on a cached copy of the service
+ * objects.
+ *
+ * @return a iterator giving access to service objects.
+ * @see java.util.Collection#iterator()
+ */
+ public Iterator iterator() {
+ List obj = (List) m_dependency.getService();
+ return new ServiceIterator(obj); // Create the service iterator with the service reference list.
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param o a object
+ * @return N/A
+ * @see java.util.Collection#remove(java.lang.Object)
+ */
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index the index
+ * @return N/A
+ * @see java.util.Collection#remove(java.lang.Object)
+ */
+ public Object remove(int index) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Gets the number of available providers.
+ *
+ * @return the number of matching service providers.
+ * @see java.util.Collection#size()
+ */
+ public int size() {
+ return m_dependency.getSize();
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ *
+ * @return a array containing available service objects.
+ * @see java.util.Collection#toArray()
+ */
+ public Object[] toArray() {
+ return toArray(new Object[0]);
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ *
+ * @param a the array into which the elements of this collection
+ * are to be stored, if it is big enough; otherwise, a new array
+ * of the same runtime type is allocated for this purpose.
+ * @return a array containing available service objects.
+ * @see java.util.Collection#toArray(java.lang.Object[])
+ */
+ public Object[] toArray(Object[] a) {
+ List list = (List) m_dependency.getService();
+ return list.toArray(a);
+ }
+
+ /**
+ * Gets the object stored at the given index.
+ *
+ * @param index the index
+ * @return the service object
+ * @see java.util.List#get(int)
+ */
+ public Object get(int index) {
+ List list = (List) m_dependency.getService();
+ return list.get(index);
+ }
+
+ /**
+ * Gets the index of the given object in the current
+ * collection.
+ *
+ * @param o the object
+ * @return the index of the object of <code>-1</code>
+ * if not found.
+ * @see java.util.List#indexOf(java.lang.Object)
+ */
+ public int indexOf(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.indexOf(o);
+ }
+
+ /**
+ * Gets the last index of the given object in the current
+ * collection.
+ *
+ * @param o the object
+ * @return the index of the object of <code>-1</code>
+ * if not found.
+ * @see java.util.List#lastIndexOf(java.lang.Object)
+ */
+ public int lastIndexOf(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.lastIndexOf(o);
+ }
+
+ /**
+ * Gets a list iterator on the current list of available service objects.
+ * The returned iterator iterates on a cached copy of the service
+ * objects.
+ *
+ * @return a iterator giving access to service objects.
+ * @see java.util.List#listIterator()
+ */
+ public ListIterator listIterator() {
+ List obj = (List) m_dependency.getService();
+ return new ServiceIterator(obj); // Create the service iterator with the service reference list.
+ }
+
+ /**
+ * Unsupported Method.
+ *
+ * @param index an index
+ * @return N/A
+ * @see java.util.List#listIterator(int)
+ */
+ public ListIterator listIterator(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unsupported Method.
+ *
+ * @param arg0 an index
+ * @param arg1 an object
+ * @return N/A
+ * @see java.util.List#set(int, Object)
+ */
+ public Object set(int arg0, Object arg1) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Returns a sublist from the current list.
+ *
+ * @param fromIndex the index of the list beginning
+ * @param toIndex the index of the list end
+ * @return the sub-list
+ * @see java.util.List#subList(int, int)
+ */
+ public List subList(int fromIndex, int toIndex) {
+ List list = (List) m_dependency.getService();
+ return list.subList(fromIndex, toIndex);
+ }
+
+ /**
+ * Iterator on a set of service objects.
+ * This iterator iterates on a cached copy of service objects.
+ */
+ private static final class ServiceIterator implements ListIterator {
+
+ /**
+ * Underlying iterator.
+ */
+ private ListIterator m_iterator;
+
+ /**
+ * Creates a Service Iterator iterating
+ * on the given set of providers.
+ *
+ * @param list the list of service object.
+ */
+ private ServiceIterator(List list) {
+ m_iterator = list.listIterator();
+ }
+
+ /**
+ * Returns <code>true</code> if the iteration has
+ * more service objects.
+ *
+ * @return <code>true</code> if the iterator has more elements.
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return m_iterator.hasNext();
+ }
+
+ /**
+ * Returns the next service objects in the iteration.
+ *
+ * @return the next service object in the iteration.
+ * @see java.util.Iterator#next()
+ */
+ public Object next() {
+ return m_iterator.next();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @param obj an object
+ * @see java.util.ListIterator#add(Object)
+ */
+ public void add(Object obj) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Checks if the is an element before the currently
+ * pointed one.
+ *
+ * @return true if there is an element before the
+ * current one.
+ * @see java.util.ListIterator#hasPrevious()
+ */
+ public boolean hasPrevious() {
+ return m_iterator.hasPrevious();
+ }
+
+ /**
+ * Gets the index of the next element.
+ *
+ * @return the index of the next element.
+ * @see java.util.ListIterator#nextIndex()
+ */
+ public int nextIndex() {
+ return m_iterator.nextIndex();
+ }
+
+
+ /**
+ * Gets the previous elements.
+ *
+ * @return the previous element
+ * @see java.util.ListIterator#previous()
+ */
+ public Object previous() {
+ return m_iterator.previous();
+ }
+
+ /**
+ * Gets the index of the previous element.
+ *
+ * @return the index of the previous element.
+ * @see java.util.ListIterator#previousIndex()
+ */
+ public int previousIndex() {
+ return m_iterator.previousIndex();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @param obj an object
+ * @see java.util.ListIterator#set(Object)
+ */
+ public void set(Object obj) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceSet.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceSet.java
new file mode 100644
index 0000000..53665a5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceSet.java
@@ -0,0 +1,453 @@
+/*
+ * 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.handlers.dependency;
+
+import java.util.*;
+
+/**
+ * Maintains a service object collection.
+ * This collection wrap the dependency to be accessible from a
+ * {@link java.util.Set}, that can be passed to helper objects (Collaborators).
+ * <p/>
+ * The {@link java.util.Collection#iterator()} method returns an {@link java.util.Iterator} iterating
+ * on a cached copy of available service objects. In the case that there are no
+ * available services, the policies act as follows:
+ * <ul>
+ * <li>'null' returns a null iterator</li>
+ * <li>'nullable' and default-implementation returns an iterator iterating on one object (the
+ * nullable or default-implementation object</li>
+ * <li>'empty' returns an empty iterator.</li>
+ * </ul>
+ * Because of FELIX-4717, this class does not implement List.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceSet implements Collection, Set {
+
+ /**
+ * The wrapped dependency.
+ */
+ private Dependency m_dependency;
+
+ /**
+ * Creates a Service Collection.
+ *
+ * @param dep the wrapped dependency
+ */
+ public ServiceSet(Dependency dep) {
+ m_dependency = dep;
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param o an object
+ * @return N/A
+ * @see java.util.Collection#add(Object)
+ */
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c an object
+ * @return N/A
+ * @see java.util.Collection#addAll(java.util.Collection)
+ */
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index an index
+ * @param obj an object
+ * @see java.util.List#add(int, Object)
+ */
+ public void add(int index, Object obj) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index an index
+ * @param c an object
+ * @return N/A
+ * @see java.util.List#addAll(int, java.util.Collection)
+ */
+ public boolean addAll(int index, Collection c) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @see java.util.Collection#clear()
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Checks if the wrapped dependency has always access to the
+ * given service object.The method allows knowing if the provider returning the
+ * service object has left.
+ *
+ * @param o the service object
+ * @return <code>true</code> if the object is still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(Object)
+ */
+ public boolean contains(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.contains(o);
+ }
+
+ /**
+ * Checks if the wrapped dependencies has always access to the
+ * given service objects.The method allows knowing if providers returning the
+ * service objects have left.
+ *
+ * @param c the set of service object
+ * @return <code>true</code> if the objects are still available,
+ * <code>false</code> otherwise.
+ * @see java.util.Collection#contains(Object)
+ */
+ public boolean containsAll(Collection c) {
+ List list = (List) m_dependency.getService();
+ return list.containsAll(c);
+ }
+
+ /**
+ * Checks if at least one provider matching with the dependency
+ * is available.
+ *
+ * @return <code>true</code> if one provider or more satisfying the
+ * dependency are available. Otherwise, returns <code>false</code>
+ * @see java.util.Collection#isEmpty()
+ */
+ public boolean isEmpty() {
+ return m_dependency.getSize() == 0;
+ }
+
+ /**
+ * Gets an iterator on the current list of available service objects.
+ * The returned iterator iterates on a cached copy of the service
+ * objects.
+ *
+ * @return a iterator giving access to service objects.
+ * @see java.util.Collection#iterator()
+ */
+ public Iterator iterator() {
+ List obj = (List) m_dependency.getService();
+ return new ServiceIterator(obj); // Create the service iterator with the service reference list.
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param o a object
+ * @return N/A
+ * @see java.util.Collection#remove(Object)
+ */
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param index the index
+ * @return N/A
+ * @see java.util.Collection#remove(Object)
+ */
+ public Object remove(int index) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Unsupported method.
+ *
+ * @param c a set of objects
+ * @return N/A
+ * @see java.util.Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException("Cannot remove elements from this collection");
+ }
+
+ /**
+ * Gets the number of available providers.
+ *
+ * @return the number of matching service providers.
+ * @see java.util.Collection#size()
+ */
+ public int size() {
+ return m_dependency.getSize();
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ *
+ * @return a array containing available service objects.
+ * @see java.util.Collection#toArray()
+ */
+ public Object[] toArray() {
+ return toArray(new Object[0]);
+ }
+
+ /**
+ * Returns an array containing available service objects.
+ * This method executed on timeout policies if no matching
+ * providers when the timeout is reached.
+ *
+ * @param a the array into which the elements of this collection
+ * are to be stored, if it is big enough; otherwise, a new array
+ * of the same runtime type is allocated for this purpose.
+ * @return a array containing available service objects.
+ * @see java.util.Collection#toArray(Object[])
+ */
+ public Object[] toArray(Object[] a) {
+ List list = (List) m_dependency.getService();
+ return list.toArray(a);
+ }
+
+ /**
+ * Gets the object stored at the given index.
+ *
+ * @param index the index
+ * @return the service object
+ * @see java.util.List#get(int)
+ */
+ public Object get(int index) {
+ List list = (List) m_dependency.getService();
+ return list.get(index);
+ }
+
+ /**
+ * Gets the index of the given object in the current
+ * collection.
+ *
+ * @param o the object
+ * @return the index of the object of <code>-1</code>
+ * if not found.
+ * @see java.util.List#indexOf(Object)
+ */
+ public int indexOf(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.indexOf(o);
+ }
+
+ /**
+ * Gets the last index of the given object in the current
+ * collection.
+ *
+ * @param o the object
+ * @return the index of the object of <code>-1</code>
+ * if not found.
+ * @see java.util.List#lastIndexOf(Object)
+ */
+ public int lastIndexOf(Object o) {
+ List list = (List) m_dependency.getService();
+ return list.lastIndexOf(o);
+ }
+
+ /**
+ * Gets a list iterator on the current list of available service objects.
+ * The returned iterator iterates on a cached copy of the service
+ * objects.
+ *
+ * @return a iterator giving access to service objects.
+ * @see java.util.List#listIterator()
+ */
+ public ListIterator listIterator() {
+ List obj = (List) m_dependency.getService();
+ return new ServiceIterator(obj); // Create the service iterator with the service reference list.
+ }
+
+ /**
+ * Unsupported Method.
+ *
+ * @param index an index
+ * @return N/A
+ * @see java.util.List#listIterator(int)
+ */
+ public ListIterator listIterator(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unsupported Method.
+ *
+ * @param arg0 an index
+ * @param arg1 an object
+ * @return N/A
+ * @see java.util.List#set(int, Object)
+ */
+ public Object set(int arg0, Object arg1) {
+ throw new UnsupportedOperationException("Cannot add elements inside this collection");
+ }
+
+ /**
+ * Returns a sublist from the current list.
+ *
+ * @param fromIndex the index of the list beginning
+ * @param toIndex the index of the list end
+ * @return the sub-list
+ * @see java.util.List#subList(int, int)
+ */
+ public List subList(int fromIndex, int toIndex) {
+ List list = (List) m_dependency.getService();
+ return list.subList(fromIndex, toIndex);
+ }
+
+ /**
+ * Iterator on a set of service objects.
+ * This iterator iterates on a cached copy of service objects.
+ */
+ private static final class ServiceIterator implements ListIterator {
+
+ /**
+ * Underlying iterator.
+ */
+ private ListIterator m_iterator;
+
+ /**
+ * Creates a Service Iterator iterating
+ * on the given set of providers.
+ *
+ * @param list the list of service object.
+ */
+ private ServiceIterator(List list) {
+ m_iterator = list.listIterator();
+ }
+
+ /**
+ * Returns <code>true</code> if the iteration has
+ * more service objects.
+ *
+ * @return <code>true</code> if the iterator has more elements.
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return m_iterator.hasNext();
+ }
+
+ /**
+ * Returns the next service objects in the iteration.
+ *
+ * @return the next service object in the iteration.
+ * @see java.util.Iterator#next()
+ */
+ public Object next() {
+ return m_iterator.next();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @param obj an object
+ * @see java.util.ListIterator#add(Object)
+ */
+ public void add(Object obj) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Checks if the is an element before the currently
+ * pointed one.
+ *
+ * @return true if there is an element before the
+ * current one.
+ * @see java.util.ListIterator#hasPrevious()
+ */
+ public boolean hasPrevious() {
+ return m_iterator.hasPrevious();
+ }
+
+ /**
+ * Gets the index of the next element.
+ *
+ * @return the index of the next element.
+ * @see java.util.ListIterator#nextIndex()
+ */
+ public int nextIndex() {
+ return m_iterator.nextIndex();
+ }
+
+
+ /**
+ * Gets the previous elements.
+ *
+ * @return the previous element
+ * @see java.util.ListIterator#previous()
+ */
+ public Object previous() {
+ return m_iterator.previous();
+ }
+
+ /**
+ * Gets the index of the previous element.
+ *
+ * @return the index of the previous element.
+ * @see java.util.ListIterator#previousIndex()
+ */
+ public int previousIndex() {
+ return m_iterator.previousIndex();
+ }
+
+ /**
+ * Unsupported operation.
+ *
+ * @param obj an object
+ * @see java.util.ListIterator#set(Object)
+ */
+ public void set(Object obj) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
new file mode 100644
index 0000000..365fa01
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
@@ -0,0 +1,100 @@
+/*
+ * 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.handlers.dependency;
+
+
+/**
+ * Object managing thread local copy of required services.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceUsage extends ThreadLocal<ServiceUsage.Usage> {
+
+ /**
+ * Structure contained in the Thread Local.
+ */
+ public static class Usage {
+
+ /**
+ * Stack Size.
+ */
+ int m_stack = 0;
+ /**
+ * Object to inject.
+ */
+ Object m_object;
+
+ /**
+ * Tracks the number of component method called
+ * in the current thread.
+ */
+ int m_componentStack = 0;
+
+ /**
+ * Increment the stack level from the first
+ * service get.
+ */
+ public void inc() {
+ m_stack++;
+ }
+
+ /**
+ * Increment the component stack level.
+ */
+ public void incComponentStack() {
+ m_componentStack++;
+ }
+
+ /**
+ * Decrement the stack level.
+ * @return true if the stack is 0 after the decrement.
+ */
+ public boolean dec() {
+ m_stack--;
+ return m_stack == 0;
+ }
+
+ /**
+ * Decrement the component stack level.
+ * @return true if the stack is 0 after the decrement.
+ */
+ public boolean decComponentStack() {
+ m_componentStack--;
+ return m_componentStack == 0;
+ }
+
+ /**
+ * Clear the service object array.
+ */
+ public void clear() {
+ m_object = null;
+ }
+
+ }
+
+ /**
+ * Initialize the cached object.
+ * @return an empty Usage object.
+ * @see java.lang.ThreadLocal#initialValue()
+ */
+ public Usage initialValue() {
+ return new Usage();
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java
new file mode 100644
index 0000000..cd86798
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java
@@ -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.
+ */
+package org.apache.felix.ipojo.handlers.lifecycle.callback;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.util.Callback;
+
+/**
+ * This class is the implementation of callback on lifecycle transition.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LifecycleCallback {
+
+ /**
+ * Invalid to Valid transition.
+ */
+ protected static final int VALIDATE = 1;
+
+ /**
+ * Valid to Invalid transition.
+ */
+ protected static final int INVALIDATE = 0;
+
+ /**
+ * Transition on which calling the callback.
+ */
+ private int m_transition;
+
+ /**
+ * Callback object.
+ */
+ private Callback m_callback;
+
+ /**
+ * LifecycleCallback constructor.
+ *
+ * @param handler : the callback handler calling the callback
+ * @param transition : transition on which calling the callback
+ * @param method : method metadata to invoke
+ */
+ public LifecycleCallback(LifecycleCallbackHandler handler, int transition, MethodMetadata method) {
+ m_transition = transition;
+ m_callback = new Callback(method, handler.getInstanceManager());
+ }
+
+ /**
+ * LifecycleCallback constructor.
+ *
+ * @param handler : the callback handler calling the callback
+ * @param transition : transition on which calling the callback
+ * @param method : method name to invoke
+ */
+ public LifecycleCallback(LifecycleCallbackHandler handler, int transition, String method) {
+ m_transition = transition;
+ m_callback = new Callback(method, new String[0], false, handler.getInstanceManager());
+ }
+
+ /**
+ * Call the callback method when the transition from inital tostate is
+ * detected.
+ *
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ protected void call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ m_callback.call();
+ }
+
+ protected int getTransition() {
+ return m_transition;
+ }
+
+ /**
+ * Get the method name of the callback.
+ * @return the method name
+ */
+ protected String getMethod() {
+ return m_callback.getMethod();
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
new file mode 100644
index 0000000..f495eb4
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
@@ -0,0 +1,178 @@
+/*
+ * 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.handlers.lifecycle.callback;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+
+/**
+ * Lifecycle callback handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LifecycleCallbackHandler extends PrimitiveHandler {
+
+ /**
+ * The list of the callback of the component.
+ */
+ private LifecycleCallback[] m_callbacks = new LifecycleCallback[0];
+
+ /**
+ * State of the instance manager (unresolved at the beginning).
+ */
+ private int m_state = InstanceManager.INVALID;
+ /**
+ * Does a POJO object be created at starting.
+ */
+ private boolean m_immediate = false;
+
+ /**
+ * Add the given callback to the callback list.
+ *
+ * @param callback : the element to add
+ */
+ private void addCallback(LifecycleCallback callback) {
+ for (int i = 0; (m_callbacks != null) && (i < m_callbacks.length); i++) {
+ if (m_callbacks[i] == callback) {
+ return;
+ }
+ }
+
+ if (m_callbacks != null && m_callbacks.length > 0) { //TODO check here if we can improve the test
+ LifecycleCallback[] newHk = new LifecycleCallback[m_callbacks.length + 1];
+ System.arraycopy(m_callbacks, 0, newHk, 0, m_callbacks.length);
+ newHk[m_callbacks.length] = callback;
+ m_callbacks = newHk;
+ } else {
+ m_callbacks = new LifecycleCallback[] { callback };
+ }
+ }
+
+ /**
+ * Configure the handler.
+ * @param metadata : the component type metadata
+ * @param configuration : the instance configuration
+ * @throws ConfigurationException : one callback metadata is not correct (either the transition or the method are not correct).
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ m_callbacks = new LifecycleCallback[0];
+
+ String imm = metadata.getAttribute("immediate");
+ m_immediate = imm != null && imm.equalsIgnoreCase("true");
+
+ PojoMetadata meta = getFactory().getPojoMetadata();
+
+ Element[] hooksMetadata = metadata.getElements("callback");
+ for (int i = 0; hooksMetadata != null && i < hooksMetadata.length; i++) {
+ String method = hooksMetadata[i].getAttribute("method");
+ if (method == null) {
+ throw new ConfigurationException("Lifecycle callback : A callback needs to contain a method attribute");
+ }
+
+ MethodMetadata met = meta.getMethod(method, new String[0]);
+
+ int transition = -1;
+ String trans = hooksMetadata[i].getAttribute("transition");
+ if (trans == null) {
+ throw new ConfigurationException("Lifecycle callback : the transition attribute is missing");
+ } else {
+ if (trans.equalsIgnoreCase("validate")) {
+ transition = LifecycleCallback.VALIDATE;
+ } else if (trans.equalsIgnoreCase("invalidate")) {
+ transition = LifecycleCallback.INVALIDATE;
+ } else {
+ throw new ConfigurationException("Lifecycle callback : Unknown or malformed transition : " + trans);
+ }
+ }
+
+ LifecycleCallback callback = null;
+ if (met == null) {
+ callback = new LifecycleCallback(this, transition, method);
+ } else {
+ callback = new LifecycleCallback(this, transition, met);
+ }
+ addCallback(callback);
+ }
+ }
+
+ /**
+ * Start the handler.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Do nothing during the start
+ }
+
+ /**
+ * Stop the handler.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ m_state = InstanceManager.INVALID;
+ }
+
+ /**
+ * When the state change call the associated callback.
+ *
+ * @param state : the new instance state.
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ int transition = -1;
+ if (m_state == ComponentInstance.INVALID && state == ComponentInstance.VALID) {
+ transition = LifecycleCallback.VALIDATE;
+ }
+ if (m_state == ComponentInstance.VALID && state == ComponentInstance.INVALID) {
+ transition = LifecycleCallback.INVALIDATE;
+ }
+
+ // Manage immediate component
+ if (m_immediate && transition == LifecycleCallback.VALIDATE && getInstanceManager().getPojoObjects() == null) {
+ getInstanceManager().getPojoObject();
+ }
+
+ for (int i = 0; i < m_callbacks.length; i++) {
+ if (m_callbacks[i].getTransition() == transition) {
+ try {
+ m_callbacks[i].call();
+ } catch (NoSuchMethodException e) {
+ error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " is not found");
+ throw new IllegalStateException(e);
+ } catch (IllegalAccessException e) {
+ error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " is not accessible");
+ throw new IllegalStateException(e);
+ } catch (InvocationTargetException e) {
+ error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " has thrown an exception : " + e.getTargetException().getMessage(), e.getTargetException());
+ throw new IllegalStateException(e.getTargetException());
+ }
+ }
+ }
+ // Update to internal state
+ m_state = state;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java
new file mode 100644
index 0000000..a8aa759
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java
@@ -0,0 +1,162 @@
+/*
+ * 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.handlers.lifecycle.controller;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+
+/**
+ * Lifecycle Controller handler.
+ * This handler allow a POJO to vote for the instance state. By setting a boolean field to true or false, the handler state changed.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ControllerHandler extends PrimitiveHandler {
+
+ /**
+ * Actual handler (i.e. field value) state
+ */
+ private boolean m_state;
+ /**
+ * The controller field name.
+ */
+ private String m_field;
+
+ /**
+ * Configure method.
+ * Look for the first 'controller' element.
+ * @param metadata : metadata
+ * @param configuration : configuration
+ * @throws ConfigurationException : the field attribute is missing or does not exist in the class.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
+ Element[] controller = metadata.getElements("controller");
+ m_field = controller[0].getAttribute("field");
+ getInstanceManager().register(new FieldMetadata(m_field, "boolean"), this);
+ }
+
+ /**
+ * Start method.
+ * This methods initializes the controller value.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // On start we should ask for the value
+ Object o = getInstanceManager().getFieldValue(m_field);
+ if (o == null || ! (o instanceof Boolean)) {
+ m_state = true;
+ } else {
+ m_state = ((Boolean) o).booleanValue();
+ }
+
+ if ( ! m_state) {
+ setValidity(false);
+ }
+ }
+
+ /**
+ * Stop method.
+ * Nothing to do.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ // Nothing to do.
+ }
+
+
+
+ /**
+ * GetterCallback.
+ * @param pojo : the pojo object on which the field is accessed
+ * Return the stored value.
+ * @param field : field name.
+ * @param value : value given by the previous handler.
+ * @return : the handler state.
+ */
+ public Object onGet(Object pojo, String field, Object value) {
+ if (m_state) {
+ return Boolean.TRUE;
+ } else {
+ return Boolean.FALSE;
+ }
+ }
+
+ /**
+ * SetterCallback.
+ * @param pojo : the pojo object on which the field is accessed
+ * Store the new field value & invalidate / validate the handler is required.
+ * @param field : field name.
+ * @param value : new value.
+ */
+ public void onSet(Object pojo, String field, Object value) {
+ if (value instanceof Boolean) {
+ boolean newValue = ((Boolean) value).booleanValue();
+ if (newValue != m_state) {
+ m_state = newValue;
+ if (m_state) {
+ ((InstanceManager) getHandlerManager()).setState(ComponentInstance.VALID);
+ setValidity(true);
+ } else {
+ ((InstanceManager) getHandlerManager()).setState(ComponentInstance.INVALID);
+ setValidity(false);
+ }
+ }
+ } else {
+ error("Boolean expected for the lifecycle controller");
+ getInstanceManager().stop();
+ }
+ }
+
+ /**
+ * Initialize the component factory.
+ * The controller field is checked to avoid configure check.
+ * @param desc : component description
+ * @param metadata : component type metadata
+ * @throws ConfigurationException : occurs if the controller field is not in the POJO class or is not a boolean.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription desc, Element metadata) throws ConfigurationException {
+ String field = null;
+ Element[] controller = metadata.getElements("controller");
+ // Use only the first controller
+ field = controller[0].getAttribute("field");
+ if (field == null) {
+ throw new ConfigurationException("Lifecycle controller : the controller element needs to contain a field attribute");
+ }
+
+ PojoMetadata method = getFactory().getPojoMetadata();
+ FieldMetadata fieldMetadata = method.getField(field);
+ if (fieldMetadata == null) {
+ throw new ConfigurationException("Lifecycle controller : The field " + field + " does not exist in the implementation class");
+ }
+
+ if (!fieldMetadata.getFieldType().equalsIgnoreCase("boolean")) {
+ throw new ConfigurationException("Lifecycle controller : The field " + field + " must be a boolean (" + fieldMetadata.getFieldType() + " found)");
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java
new file mode 100644
index 0000000..a1d6899
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java
@@ -0,0 +1,76 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.osgi.framework.ServiceFactory;
+
+/**
+ * Creation strategy to creation service object.
+ * This class is extended by all service object
+ * creation policy.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class CreationStrategy implements ServiceFactory {
+ /**
+ * Method called when the service is registered.
+ * @param instance the instance registering the service.
+ * @param interfaces the exposed service specification interfaces
+ * @param props the published properties.
+ */
+ public abstract void onPublication(InstanceManager instance, String[] interfaces, Properties props);
+ /**
+ * Method called when the service in unregistered.
+ */
+ public abstract void onUnpublication();
+
+ /**
+ * Checks if the given method object is the
+ * {@link org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)}
+ * method.
+ * @param method the method to check
+ * @return <code>true</code> if the method is the getService method
+ * <code>false</code> otherwise.
+ */
+ public static boolean isGetServiceMethod(Method method) {
+ Class[] params = method.getParameterTypes();
+ return method.getName().equals("getService")
+ && params.length == 1
+ && params[0].getName().equals(ComponentInstance.class.getName());
+ }
+
+ /**
+ * Checks if the given method object is the
+ * {@link org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, Object)}
+ * method.
+ * @param method the method to check
+ * @return <code>true</code> if the method is the ungetService method
+ * <code>false</code> otherwise.
+ */
+ public static boolean isUngetServiceMethod(Method method) {
+ Class[] params = method.getParameterTypes();
+ return method.getName().equals("ungetService")
+ && params.length == 2
+ && params[0].getName().equals(ComponentInstance.class.getName());
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
new file mode 100644
index 0000000..b50a969
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
@@ -0,0 +1,1160 @@
+/*
+ * 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.handlers.providedservice;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Property;
+import org.apache.felix.ipojo.util.SecurityHelper;
+import org.osgi.framework.*;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.*;
+
+/**
+ * Provided Service represent a provided service by the component.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedService implements ServiceFactory {
+
+ /**
+ * Service State : REGISTRED.
+ */
+ public static final int REGISTERED = 1;
+
+ /**
+ * Service State : UNREGISTRED.
+ */
+ public static final int UNREGISTERED = 0;
+
+ /**
+ * Factory Policy : SINGLETON_FACTORY.
+ */
+ public static final int SINGLETON_STRATEGY = 0;
+
+ /**
+ * Factory policy : SERVICE_FACTORY.
+ */
+ public static final int SERVICE_STRATEGY = 1;
+
+ /**
+ * Factory policy : STATIC_FACTORY.
+ */
+ public static final int STATIC_STRATEGY = 2;
+
+ /**
+ * Factory policy : INSTANCE.
+ * Creates one service object per instance consuming the service.
+ */
+ public static final int INSTANCE_STRATEGY = 3;
+
+ /**
+ * Factory policy : CUSTOMIZED.
+ * Custom creation strategy
+ */
+ public static final int CUSTOM_STRATEGY = -1;
+ public static final String ALL_SPECIFICATIONS_FOR_CONTROLLERS = "ALL";
+
+ /**
+ * At this time, it is only the java interface full name.
+ */
+ private String[] m_serviceSpecifications = new String[0];
+
+ /**
+ * The service registration. is null when the service is not registered.
+ * m_serviceRegistration : ServiceRegistration
+ */
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ * Link to the owner handler. m_handler : Provided Service Handler
+ */
+ private ProvidedServiceHandler m_handler;
+
+ /**
+ * The map of properties.
+ */
+ private Map<String, Property> m_properties = new TreeMap<String, Property>();
+
+ /**
+ * Service providing policy.
+ */
+ private final int m_policy;
+
+ /**
+ * Service Object creation policy.
+ */
+ private final CreationStrategy m_strategy;
+
+ /**
+ * Were the properties updated during the processing.
+ */
+ private volatile boolean m_wasUpdated;
+
+ /**
+ * Service Controller.
+ */
+ private Map<String, ServiceController> m_controllers = new HashMap<String, ServiceController>();
+
+ /**
+ * Post-Registration callback.
+ */
+ private Callback m_postRegistration;
+
+ /**
+ * Post-Unregistration callback.
+ */
+ private Callback m_postUnregistration;
+
+ /**
+ * The published properties.
+ */
+ private Dictionary m_publishedProperties = new Properties();
+
+ /**
+ * The provided service listeners.
+ */
+ private List<ProvidedServiceListener> m_listeners = new ArrayList<ProvidedServiceListener>();
+
+ /**
+ * Creates a provided service object.
+ *
+ * @param handler the the provided service handler.
+ * @param specification the specifications provided by this provided service
+ * @param factoryPolicy the service providing policy
+ * @param creationStrategyClass the customized service object creation strategy.
+ * @param conf the instance configuration.
+ */
+ public ProvidedService(ProvidedServiceHandler handler, String[] specification, int factoryPolicy, Class creationStrategyClass, Dictionary conf) {
+ CreationStrategy strategy;
+ m_handler = handler;
+
+ m_serviceSpecifications = specification;
+
+ if (creationStrategyClass == null) {
+ m_policy = factoryPolicy;
+ } else {
+ m_policy = CUSTOM_STRATEGY;
+ }
+
+ // Add instance name, factory name and factory version is set.
+ try {
+ addProperty(new Property(Factory.INSTANCE_NAME_PROPERTY, null, null, handler.getInstanceManager().getInstanceName(), String.class.getName(), handler.getInstanceManager(), handler));
+ addProperty(new Property("factory.name", null, null, handler.getInstanceManager().getFactory().getFactoryName(), String.class.getName(), handler.getInstanceManager(), handler));
+
+ if (handler.getInstanceManager().getFactory().getVersion() != null) {
+ addProperty(new Property(Factory.FACTORY_VERSION_PROPERTY, null, null, handler.getInstanceManager().getFactory().getVersion(), String.class.getName(), handler.getInstanceManager(), handler));
+ }
+
+ // Add the service.* if defined
+ if (conf.get(Constants.SERVICE_PID) != null) {
+ addProperty(new Property(Constants.SERVICE_PID, null, null, (String) conf.get(Constants.SERVICE_PID), String.class.getName(), handler.getInstanceManager(), handler));
+ }
+ if (conf.get(Constants.SERVICE_RANKING) != null) {
+ addProperty(new Property(Constants.SERVICE_RANKING, null, null, (String) conf.get(Constants.SERVICE_RANKING), "int", handler.getInstanceManager(), handler));
+ }
+ if (conf.get(Constants.SERVICE_VENDOR) != null) {
+ addProperty(new Property(Constants.SERVICE_VENDOR, null, null, (String) conf.get(Constants.SERVICE_VENDOR), String.class.getName(), handler.getInstanceManager(), handler));
+ }
+ if (conf.get(Constants.SERVICE_DESCRIPTION) != null) {
+ addProperty(new Property(Constants.SERVICE_DESCRIPTION, null, null, (String) conf.get(Constants.SERVICE_DESCRIPTION), String.class.getName(), handler.getInstanceManager(), handler));
+ }
+
+ } catch (ConfigurationException e) {
+ m_handler.error("An exception occurs when adding instance.name and factory.name property : " + e.getMessage());
+ }
+
+ if (creationStrategyClass != null) {
+ try {
+ strategy = (CreationStrategy) creationStrategyClass.newInstance();
+ } catch (IllegalAccessException e) {
+ strategy = null;
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] The customized service object creation policy "
+ + "(" + creationStrategyClass.getName() + ") is not accessible: "
+ + e.getMessage(), e);
+ getInstanceManager().stop();
+ } catch (InstantiationException e) {
+ strategy = null;
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] The customized service object creation policy "
+ + "(" + creationStrategyClass.getName() + ") cannot be instantiated: "
+ + e.getMessage(), e);
+ getInstanceManager().stop();
+ }
+ } else {
+ switch (factoryPolicy) {
+ case SINGLETON_STRATEGY:
+ strategy = new SingletonStrategy();
+ break;
+ case SERVICE_STRATEGY:
+ case STATIC_STRATEGY:
+ // In this case, we need to try to create a new pojo object,
+ // the factory method will handle the creation.
+ strategy = new FactoryStrategy();
+ break;
+ case INSTANCE_STRATEGY:
+ strategy = new PerInstanceStrategy();
+ break;
+ // Other policies:
+ // Thread : one service object per asking thread
+ // Consumer : one service object per consumer
+ default:
+ strategy = null;
+ List specs = Arrays.asList(m_serviceSpecifications);
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] Unknown creation policy for " + specs + " : "
+ + factoryPolicy);
+ getInstanceManager().stop();
+ break;
+ }
+ }
+ m_strategy = strategy;
+ }
+
+ /**
+ * Add properties to the provided service.
+ *
+ * @param props : the properties to attached to the service registration
+ */
+ protected void setProperties(Property[] props) {
+ for (Property prop : props) {
+ addProperty(prop);
+ }
+ }
+
+ /**
+ * Add the given property to the property list.
+ *
+ * @param prop : the element to add
+ */
+ private synchronized void addProperty(Property prop) {
+ m_properties.put(prop.getName(), prop);
+ }
+
+ /**
+ * Remove a property.
+ *
+ * @param name : the property to remove
+ * @return <code>true</code> if the property was removed,
+ * <code>false</code> otherwise.
+ */
+ private synchronized boolean removeProperty(String name) {
+ return m_properties.remove(name) != null;
+ }
+
+ /**
+ * Get the service reference of the service registration.
+ *
+ * @return the service reference of the provided service (null if the
+ * service is not published).
+ */
+ public ServiceReference getServiceReference() {
+ if (m_serviceRegistration == null) {
+ return null;
+ } else {
+ return m_serviceRegistration.getReference();
+ }
+ }
+
+ /**
+ * Returns a service object for the dependency.
+ *
+ * @param bundle : the bundle
+ * @param registration : the service registration of the registered service
+ * @return a new service object or a already created service object (in the case of singleton) or <code>null</code>
+ * if the instance is no more valid.
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ if (getInstanceManager().getState() == InstanceManager.VALID) {
+ return m_strategy.getService(bundle, registration);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * The unget method.
+ *
+ * @param bundle : bundle
+ * @param registration : service registration
+ * @param service : service object
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle,
+ * org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ m_strategy.ungetService(bundle, registration, service);
+ }
+
+ /**
+ * Registers the service. The service object must be able to serve this
+ * service.
+ * This method also notifies the creation strategy of the publication.
+ */
+ public void registerService() {
+ ServiceRegistration reg = null;
+ Properties serviceProperties = null;
+ // Do not have to be in the synchronized block, immutable.
+ final BundleContext bc = m_handler.getInstanceManager().getContext();
+
+ synchronized (this) {
+ if (m_serviceRegistration != null) {
+ return;
+ } else {
+ if (m_handler.getInstanceManager().getState() == ComponentInstance.VALID && isAtLeastAServiceControllerValid()) {
+ // Security check
+ if (SecurityHelper.hasPermissionToRegisterServices(
+ m_serviceSpecifications, bc) && SecurityHelper.canRegisterService(bc)) {
+ serviceProperties = getServiceProperties();
+ } else {
+ throw new SecurityException("The bundle "
+ + bc.getBundle().getBundleId()
+ + " does not have the"
+ + " permission to register the services "
+ + Arrays.asList(m_serviceSpecifications));
+ }
+ } else {
+ // We don't have to do anything.
+ return;
+ }
+ }
+ }
+
+ // Registration must be done outside of the synchronized block.
+ m_strategy.onPublication(getInstanceManager(),
+ getServiceSpecificationsToRegister(),
+ serviceProperties);
+ reg = bc.registerService(
+ getServiceSpecificationsToRegister(), this,
+ (Dictionary) serviceProperties);
+
+ boolean update = false;
+ synchronized (this) {
+ if (m_serviceRegistration != null) {
+ // Oh oh the service was registered twice. Unregister the last one
+ reg.unregister();
+ return;
+ } else {
+ m_serviceRegistration = reg;
+ }
+
+ // An update may happen during the registration, re-check and apply.
+ // This must be call outside the synchronized block.
+ // If the registration is null, the security helper returns false.
+ if (m_wasUpdated && SecurityHelper.canUpdateService(reg)) {
+ serviceProperties = getServiceProperties();
+ update = true;
+ }
+ }
+
+ if (update) {
+ reg.setProperties(serviceProperties);
+ }
+
+ synchronized (this) {
+ m_publishedProperties = serviceProperties;
+ m_wasUpdated = false;
+
+ // Call the post-registration callback in the same thread holding
+ // the monitor lock.
+ // This allows to be sure that the callback is called once per
+ // registration.
+ // But the callback must take care to not create a deadlock
+ if (m_postRegistration != null) {
+ try {
+ m_postRegistration
+ .call(new Object[]{m_serviceRegistration
+ .getReference()});
+ } catch (Exception e) {
+ m_handler.error(
+ "Cannot invoke the post-registration callback "
+ + m_postRegistration.getMethod(), e);
+ }
+ }
+ }
+
+ // Notify: ProvidedServiceListeners.serviceRegistered()
+ notifyListeners(+1);
+
+ }
+
+ /**
+ * Withdraws the service from the service registry.
+ */
+ public void unregisterService() {
+ ServiceReference ref = null;
+ synchronized (this) {
+ // Create a copy of the service reference in the case we need
+ // to inject it to the post-unregistration callback.
+ if (m_serviceRegistration != null) {
+ ref = m_serviceRegistration.getReference();
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+ }
+
+ m_strategy.onUnpublication();
+
+ // Call the post-unregistration callback in the same thread holding the monitor lock.
+ // This allows to be sure that the callback is called once per unregistration.
+ // But the callback must take care to not create a deadlock
+ if (m_postUnregistration != null && ref != null) {
+ try {
+ m_postUnregistration.call(new Object[]{ref});
+ } catch (Exception e) {
+ m_handler.error("Cannot invoke the post-unregistration callback " + m_postUnregistration.getMethod(), e);
+ }
+ }
+ }
+
+ // Notify: ProvidedServiceListeners.serviceUnregistered()
+ if (ref != null) {
+ notifyListeners(-1);
+ }
+
+ }
+
+ /**
+ * Get the current provided service state.
+ *
+ * @return The state of the provided service.
+ */
+ public int getState() {
+ if (m_serviceRegistration == null) {
+ return UNREGISTERED;
+ } else {
+ return REGISTERED;
+ }
+ }
+
+ protected InstanceManager getInstanceManager() {
+ return m_handler.getInstanceManager();
+ }
+
+ /**
+ * Return the list of properties attached to this service. This list
+ * contains only property where a value are assigned.
+ * <p/>
+ * This method is called while holding the monitor lock.
+ *
+ * @return the properties attached to the provided service.
+ */
+ private Properties getServiceProperties() {
+ // Build the service properties list
+ Properties serviceProperties = new Properties();
+ for (Property p : m_properties.values()) {
+ final Object value = p.getValue();
+ if (value != null && value != Property.NO_VALUE) {
+ serviceProperties.put(p.getName(), value);
+ }
+ }
+ return serviceProperties;
+ }
+
+ /**
+ * Get the list of properties attached to the service registration.
+ *
+ * @return the properties attached to the provided service.
+ */
+ public synchronized Property[] getProperties() {
+ return m_properties.values().toArray(new Property[m_properties.size()]);
+ }
+
+ /**
+ * Update the service properties. The new list of properties is sent to
+ * the service registry.
+ */
+ public void update() {
+ boolean doCallListener = false;
+ synchronized (this) {
+ // Update the service registration
+ if (m_serviceRegistration != null) {
+ Properties updated = getServiceProperties();
+ Dictionary oldProps = (Dictionary) ((Properties) m_publishedProperties).clone();
+ Dictionary newProps = (Dictionary) (updated.clone());
+
+ // Remove keys that must not be compared
+ newProps.remove(Factory.INSTANCE_NAME_PROPERTY);
+ oldProps.remove(Factory.INSTANCE_NAME_PROPERTY);
+ newProps.remove(Constants.SERVICE_ID);
+ oldProps.remove(Constants.SERVICE_ID);
+ newProps.remove(Constants.SERVICE_PID);
+ oldProps.remove(Constants.SERVICE_PID);
+ newProps.remove("factory.name");
+ oldProps.remove("factory.name");
+ newProps.remove(ConfigurationAdmin.SERVICE_FACTORYPID);
+ oldProps.remove(ConfigurationAdmin.SERVICE_FACTORYPID);
+
+ // Trigger the update only if the properties have changed.
+
+ // First check, are the size equals
+ if (oldProps.size() != newProps.size()) {
+ if (SecurityHelper.canUpdateService(m_serviceRegistration)) {
+ m_handler.info("Updating Registration : " + oldProps.size() + " / " + newProps.size());
+ m_publishedProperties = updated;
+ m_serviceRegistration.setProperties(updated);
+ doCallListener = true;
+ }
+ } else {
+ // Check changes
+ Enumeration keys = oldProps.keys();
+ boolean hasChanged = false;
+ while (!hasChanged && keys.hasMoreElements()) {
+ String k = (String) keys.nextElement();
+ Object val = oldProps.get(k);
+ if (!val.equals(updated.get(k))) {
+ hasChanged = true;
+ }
+ }
+ if (hasChanged && SecurityHelper.canUpdateService(m_serviceRegistration)) {
+ m_handler.info("Updating Registration : " + updated);
+ m_publishedProperties = updated;
+ m_serviceRegistration.setProperties(updated);
+ doCallListener = true;
+ }
+ }
+ } else {
+ // Need to be updated later.
+ m_wasUpdated = true;
+ }
+ }
+ if (doCallListener) {
+ // Notify: ProvidedServiceListeners.serviceUpdated()
+ notifyListeners(0);
+ }
+ }
+
+ /**
+ * Add properties to the list.
+ *
+ * @param props : properties to add
+ */
+ protected void addProperties(Dictionary props) {
+ Enumeration keys = props.keys();
+ boolean updated = false;
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ Object value = props.get(key);
+
+ // m_properties can be modified by another thread, we need to make a stack confinement
+ Property property;
+ synchronized (this) {
+ property = m_properties.get(key);
+ }
+
+ if (property != null) {
+ // Already existing property
+ if (property.getValue() == null || !value.equals(property.getValue())) {
+ property.setValue(value);
+ updated = true;
+ }
+ } else {
+ try {
+ // Create the property.
+ property = new Property(key, null, null, value, getInstanceManager(), m_handler);
+ addProperty(property);
+ updated = true;
+ } catch (ConfigurationException e) {
+ m_handler.error("The propagated property " + key + " cannot be created correctly : " + e.getMessage());
+ }
+ }
+ }
+
+ if (updated) {
+ m_handler.info("Update triggered by adding properties " + props);
+ update();
+ }
+ }
+
+ /**
+ * Remove properties from the list.
+ *
+ * @param props : properties to remove
+ */
+ protected void deleteProperties(Dictionary props) {
+ Enumeration keys = props.keys();
+ boolean mustUpdate = false;
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ mustUpdate = mustUpdate || removeProperty(key);
+ }
+
+ if (mustUpdate) {
+ m_handler.info("Update triggered when removing properties : " + props);
+ update();
+ }
+ }
+
+ /**
+ * Get the published service specifications.
+ *
+ * @return the list of provided service specifications (i.e. java
+ * interface).
+ */
+ public String[] getServiceSpecifications() {
+ return m_serviceSpecifications;
+ }
+
+ /**
+ * Get the service registration.
+ *
+ * @return the service registration of this service.
+ */
+ public ServiceRegistration getServiceRegistration() {
+ return m_serviceRegistration;
+ }
+
+ /**
+ * Sets the service controller on this provided service.
+ *
+ * @param field the field attached to this controller
+ * @param value the value the initial value
+ * @param specification the target specification, if <code>null</code>
+ * affect all specifications.
+ */
+ public void setController(String field, boolean value, String specification) {
+ if (specification == null) {
+ m_controllers.put(ALL_SPECIFICATIONS_FOR_CONTROLLERS, new ServiceController(field, value));
+ } else {
+ m_controllers.put(specification, new ServiceController(field, value));
+
+ }
+ }
+
+ /**
+ * Gets the service controller attached to the given field.
+ *
+ * @param field the field name
+ * @return the service controller, {@code null} if there is no service controller attached to the given field
+ * name.
+ */
+ public ServiceController getController(String field) {
+ for (ServiceController controller : m_controllers.values()) {
+ if (field.equals(controller.m_field)) {
+ return controller;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the service controller handling the service publishing the given specification.
+ *
+ * @param spec the specification (qualified class name)
+ * @return the service controller, {@code null} if there is no service controller handling the service publishing
+ * the given service specification
+ */
+ public ServiceController getControllerBySpecification(String spec) {
+ return m_controllers.get(spec);
+ }
+
+ /**
+ * Checks if at least one service controller is valid.
+ *
+ * @return <code>true</code> if one service controller at least
+ * is valid.
+ */
+ private boolean isAtLeastAServiceControllerValid() {
+ // No controller
+ if (m_controllers.isEmpty()) {
+ return true;
+ }
+
+ for (ServiceController controller : m_controllers.values()) {
+ if (controller.getValue()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String[] getServiceSpecificationsToRegister() {
+ if (m_controllers.isEmpty()) {
+ return m_serviceSpecifications;
+ }
+
+ ArrayList<String> l = new ArrayList<String>();
+ if (m_controllers.containsKey(ALL_SPECIFICATIONS_FOR_CONTROLLERS)) {
+ ServiceController ctrl = m_controllers.get(ALL_SPECIFICATIONS_FOR_CONTROLLERS);
+ if (ctrl.m_value) {
+ l.addAll(Arrays.asList(m_serviceSpecifications));
+ }
+ }
+
+ for (String spec : m_controllers.keySet()) {
+ ServiceController ctrl = m_controllers.get(spec);
+ if (ctrl.m_value) {
+ if (!ALL_SPECIFICATIONS_FOR_CONTROLLERS.equals(spec)) { // Already added.
+ if (!l.contains(spec)) {
+ l.add(spec);
+ }
+ }
+ } else {
+ l.remove(spec);
+ }
+ }
+
+ return l.toArray(new String[l.size()]);
+
+ }
+
+ public void setPostRegistrationCallback(Callback cb) {
+ m_postRegistration = cb;
+ }
+
+ public void setPostUnregistrationCallback(Callback cb) {
+ m_postUnregistration = cb;
+ }
+
+ public int getPolicy() {
+ return m_policy;
+ }
+
+ public Class<? extends CreationStrategy> getCreationStrategy() {
+ return m_strategy.getClass();
+ }
+
+ /**
+ * Add the given listener to the provided service handler's list of listeners.
+ *
+ * @param listener the {@code ProvidedServiceListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(ProvidedServiceListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("null listener");
+ }
+ synchronized (m_listeners) {
+ m_listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the given listener from the provided service handler's list of listeners.
+ *
+ * @param listener the {@code ProvidedServiceListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ * @throws NoSuchElementException if {@code listener} wasn't present the in provided service handler's list of listeners
+ */
+ public void removeListener(ProvidedServiceListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("null listener");
+ }
+ synchronized (m_listeners) {
+ // We definitely cannot rely on listener's equals method...
+ // ...so we need to manually search for the listener, using ==.
+ int i = -1;
+ for (int j = m_listeners.size() - 1; j >= 0; j--) {
+ if (m_listeners.get(j) == listener) {
+ // Found!
+ i = j;
+ break;
+ }
+ }
+ if (i != -1) {
+ m_listeners.remove(i);
+ } else {
+ throw new NoSuchElementException("no such listener");
+ }
+ }
+ }
+
+ /**
+ * Notify all listeners that a change has occurred in this provided service.
+ *
+ * @param direction the "direction" of the change (+1:registration, 0:update, -1:unregistration)
+ */
+ private void notifyListeners(int direction) {
+ // Get a snapshot of the listeners
+ List<ProvidedServiceListener> tmp;
+ synchronized (m_listeners) {
+ tmp = new ArrayList<ProvidedServiceListener>(m_listeners);
+ }
+ // Do notify, outside the m_listeners lock
+ for (ProvidedServiceListener l : tmp) {
+ try {
+ if (direction > 0) {
+ l.serviceRegistered(m_handler.getInstanceManager(), this);
+ } else if (direction < 0) {
+ l.serviceUnregistered(m_handler.getInstanceManager(), this);
+ } else {
+ l.serviceModified(m_handler.getInstanceManager(), this);
+ }
+ } catch (Throwable e) {
+ // Put a warning on the logger, and continue
+ m_handler.warn(
+ String.format(
+ "[%s] A ProvidedServiceListener has failed: %s",
+ m_handler.getInstanceManager().getInstanceName(),
+ e.getMessage())
+ , e);
+ }
+ }
+ }
+
+ /**
+ * Removes all the listeners from this provided service before it gets disposed.
+ */
+ public void cleanup() {
+ synchronized (m_listeners) {
+ m_listeners.clear();
+ }
+ }
+
+ /**
+ * Service Controller.
+ */
+ class ServiceController {
+ /**
+ * The controller value.
+ */
+ private boolean m_value;
+ /**
+ * The field attached to this controller.
+ */
+ private final String m_field;
+
+ /**
+ * Creates a ServiceController.
+ *
+ * @param field the field
+ * @param value the initial value
+ */
+ public ServiceController(String field, boolean value) {
+ m_field = field;
+ m_value = value;
+ }
+
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ */
+ public boolean getValue() {
+ synchronized (ProvidedService.this) {
+ return m_value;
+ }
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value the value
+ */
+ public void setValue(Boolean value) {
+ synchronized (ProvidedService.this) {
+ if (value != m_value) {
+ // If there is a change to the ServiceController value then
+ // we will
+ // need to modify the registrations.
+ m_value = value;
+ unregisterService();
+ if (getServiceSpecificationsToRegister().length != 0) {
+ registerService();
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Singleton creation strategy.
+ * This strategy just creates one service object and
+ * returns always the same.
+ */
+ private class SingletonStrategy extends CreationStrategy {
+
+ /**
+ * The service is going to be registered.
+ *
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) {
+ }
+
+ /**
+ * The service was unpublished.
+ *
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ }
+
+ /**
+ * A service object is required.
+ *
+ * @param arg0 the bundle requiring the service object.
+ * @param arg1 the service registration.
+ * @return the first pojo object.
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ return m_handler.getInstanceManager().getPojoObject();
+ }
+
+ /**
+ * A service object is released.
+ *
+ * @param arg0 the bundle
+ * @param arg1 the service registration
+ * @param arg2 the get service object.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) {
+ }
+
+ }
+
+ /**
+ * Service object creation policy following the OSGi Service Factory
+ * policy {@link ServiceFactory}.
+ */
+ private class FactoryStrategy extends CreationStrategy {
+
+ /**
+ * The service is going to be registered.
+ *
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) {
+ }
+
+ /**
+ * The service is unpublished.
+ *
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ }
+
+ /**
+ * OSGi Service Factory getService method.
+ * Returns a new service object per asking bundle.
+ * This object is then cached by the framework.
+ *
+ * @param arg0 the bundle requiring the service
+ * @param arg1 the service registration
+ * @return the service object for the asking bundle
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ return m_handler.getInstanceManager().createPojoObject();
+ }
+
+ /**
+ * OSGi Service Factory unget method.
+ * Deletes the created object for the asking bundle.
+ *
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the created service object returned for this bundle
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) {
+ m_handler.getInstanceManager().deletePojoObject(arg2);
+ }
+ }
+
+
+ /**
+ * Service object creation policy creating a service object per asking iPOJO component
+ * instance. This creation policy follows the iPOJO Service Factory interaction pattern
+ * and does no support 'direct' invocation.
+ */
+ private class PerInstanceStrategy extends CreationStrategy implements IPOJOServiceFactory, InvocationHandler {
+ /**
+ * Map [ComponentInstance->ServiceObject] storing created service objects.
+ */
+ private Map/*<ComponentInstance, ServiceObject>*/ m_instances = new HashMap();
+
+ /**
+ * A method is invoked on the proxy object.
+ * If the method is the {@link IPOJOServiceFactory#getService(ComponentInstance)}
+ * method, this method creates a service object if not already created for the asking
+ * component instance.
+ * If the method is {@link IPOJOServiceFactory#ungetService(ComponentInstance, Object)}
+ * the service object is unget (i.e. removed from the map and deleted).
+ * In all other cases, a {@link UnsupportedOperationException} is thrown as this policy
+ * requires to use the {@link IPOJOServiceFactory} interaction pattern.
+ *
+ * @param arg0 the proxy object
+ * @param arg1 the called method
+ * @param arg2 the arguments
+ * @return the service object attached to the asking instance for 'get',
+ * <code>null</code> for 'unget',
+ * a {@link UnsupportedOperationException} for all other methods.
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(Object arg0, Method arg1, Object[] arg2) {
+ if (isGetServiceMethod(arg1)) {
+ return getService((ComponentInstance) arg2[0]);
+ }
+
+ if (isUngetServiceMethod(arg1)) {
+ ungetService((ComponentInstance) arg2[0], arg2[1]);
+ return null;
+ }
+
+ // Regular methods from java.lang.Object : equals and hashCode
+ if (arg1.getName().equals("equals") && arg2 != null && arg2.length == 1) {
+ return this.equals(arg2[0]);
+ }
+
+ if (arg1.getName().equals("hashCode")) {
+ return this.hashCode();
+ }
+
+ throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ + "Before calling the service, call the getService(ComponentInstance) method to get "
+ + "the service object. - Method called: " + arg1.getName());
+ }
+
+ /**
+ * A service object is required.
+ * This policy returns a service object per asking instance.
+ *
+ * @param instance the instance requiring the service object
+ * @return the service object for this instance
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)
+ */
+ public Object getService(ComponentInstance instance) {
+ Object obj = m_instances.get(instance);
+ if (obj == null) {
+ obj = m_handler.getInstanceManager().createPojoObject();
+ m_instances.put(instance, obj);
+ }
+ return obj;
+ }
+
+ /**
+ * A service object is unget.
+ * The service object is removed from the map and deleted.
+ *
+ * @param instance the instance releasing the service
+ * @param svcObject the service object
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, java.lang.Object)
+ */
+ public void ungetService(ComponentInstance instance, Object svcObject) {
+ Object pojo = m_instances.remove(instance);
+ m_handler.getInstanceManager().deletePojoObject(pojo);
+ }
+
+ /**
+ * The service is going to be registered.
+ *
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) {
+ }
+
+ /**
+ * The service is going to be unregistered.
+ * The instance map is cleared. Created object are disposed.
+ *
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ Collection col = m_instances.values();
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ m_handler.getInstanceManager().deletePojoObject(it.next());
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * OSGi Service Factory getService method.
+ *
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @return a proxy implementing the {@link IPOJOServiceFactory}
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ Object proxy = Proxy.newProxyInstance(getInstanceManager().getClazz().getClassLoader(),
+ getSpecificationsWithIPOJOServiceFactory(m_serviceSpecifications, m_handler.getInstanceManager().getContext()), this);
+ return proxy;
+ }
+
+ /**
+ * OSGi Service factory unget method.
+ * Does nothing.
+ *
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the service object created for this bundle.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) {
+ }
+
+ /**
+ * Utility method returning the class array of provided service
+ * specification and the {@link IPOJOServiceFactory} interface.
+ *
+ * @param specs the published service interface
+ * @param bc the bundle context, used to load classes
+ * @return the class array containing provided service specification and
+ * the {@link IPOJOServiceFactory} class.
+ */
+ private Class[] getSpecificationsWithIPOJOServiceFactory(String[] specs, BundleContext bc) {
+ Class[] classes = new Class[specs.length + 1];
+ int i = 0;
+ for (i = 0; i < specs.length; i++) {
+ try {
+ classes[i] = bc.getBundle().loadClass(specs[i]);
+ } catch (ClassNotFoundException e) {
+ // Should not happen.
+ }
+ }
+ classes[i] = IPOJOServiceFactory.class;
+ return classes;
+ }
+
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceDescription.java
new file mode 100644
index 0000000..310fee0
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceDescription.java
@@ -0,0 +1,195 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.util.Property;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Provided Service Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceDescription {
+
+ /**
+ * State : the service is unregistered.
+ */
+ public static final int UNREGISTERED = ProvidedService.UNREGISTERED;
+
+ /**
+ * State : the service is registered.
+ */
+ public static final int REGISTERED = ProvidedService.REGISTERED;
+
+ /**
+ * The describe provided service.
+ */
+ private final ProvidedService m_ps;
+
+ /**
+ * Constructor.
+ * @param ps the described provided service.
+ */
+ public ProvidedServiceDescription(ProvidedService ps) {
+ m_ps = ps;
+ }
+
+ /**
+ * Gets the represented provided service.
+ * @return the provided service
+ */
+ public ProvidedService getProvidedService() {
+ return m_ps;
+ }
+
+ /**
+ * Gets the list of provided service specifications.
+ * @return the provided contract name.
+ */
+ public String[] getServiceSpecifications() {
+ return m_ps.getServiceSpecifications();
+ }
+
+ /**
+ * Gets the list of properties.
+ * A copy of the actual property set is returned.
+ * @return the properties.
+ */
+ public Properties getProperties() {
+ Properties props = new Properties();
+ org.apache.felix.ipojo.util.Property[] ps = m_ps.getProperties();
+ for (int i = 0; i < ps.length; i++) {
+ if (ps[i].getValue() != Property.NO_VALUE) {
+ props.put(ps[i].getName(), ps[i].getValue());
+ }
+ }
+ return props;
+ }
+
+ /**
+ * Adds and Updates service properties.
+ * Existing properties are updated.
+ * New ones are added.
+ * @param props the new properties
+ */
+ public void addProperties(Dictionary props) {
+ m_ps.addProperties(props);
+ }
+
+ /**
+ * Removes service properties.
+ * @param props the properties to remove
+ */
+ public void removeProperties(Dictionary props) {
+ m_ps.deleteProperties(props);
+ }
+
+ /**
+ * Gets provided service state.
+ * @return the state of the provided service (UNREGISTERED | REGISTERED).
+ */
+ public int getState() {
+ return m_ps.getState();
+ }
+
+ /**
+ * Gets the controller value as a String.
+ * @return the value
+ */
+ public String getController() {
+ if (m_ps.getControllerBySpecification("ALL") == null) {
+ return null;
+ } else {
+ return String.valueOf(m_ps.getControllerBySpecification("ALL").getValue());
+ }
+ }
+
+ /**
+ * Gets the controller value as a String.
+ * @param specification
+ * @return the value
+ */
+ public String getController(String specification) {
+ if (m_ps.getControllerBySpecification(specification) == null) {
+ return null;
+ } else {
+ return String.valueOf(m_ps.getControllerBySpecification(specification).getValue());
+ }
+ }
+
+ /**
+ * Gets the service reference.
+ * @return the service reference (null if the service is unregistered).
+ */
+ public ServiceReference getServiceReference() {
+ return m_ps.getServiceReference();
+ }
+
+ /**
+ * Gets the 'main' service object.
+ * @return the 'main' service object or <code>null</code>
+ * if no service object are created.
+ */
+ public Object getService() {
+ Object[] objs = m_ps.getInstanceManager().getPojoObjects();
+ if (objs == null) {
+ return null;
+ } else {
+ return objs[0];
+ }
+ }
+
+ public Object[] getServices() {
+ return m_ps.getInstanceManager().getPojoObjects();
+ }
+
+ public int getPolicy() {
+ return m_ps.getPolicy();
+ }
+
+ public Class<? extends CreationStrategy> getCreationStrategy() {
+ return m_ps.getCreationStrategy();
+ }
+
+ /**
+ * Add the given listener to the provided service handler's list of listeners.
+ *
+ * @param listener the {@code ProvidedServiceListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(ProvidedServiceListener listener) {
+ m_ps.addListener(listener);
+ }
+
+ /**
+ * Remove the given listener from the provided service handler's list of listeners.
+ *
+ * @param listener the {@code ProvidedServiceListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ * @throws java.util.NoSuchElementException if {@code listener} wasn't present the in provided service handler's list of listeners
+ */
+ public void removeListener(ProvidedServiceListener listener) {
+ m_ps.removeListener(listener);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
new file mode 100644
index 0000000..8e3a88f
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
@@ -0,0 +1,682 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Pojo;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.dependency.Dependency;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService.ServiceController;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.apache.felix.ipojo.util.Logger;
+import org.apache.felix.ipojo.util.Property;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Composite Provided Service Handler.
+ * This handler manage the service providing for a composition.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandler extends PrimitiveHandler {
+
+ /**
+ * The list of the provided service.
+ */
+ private Set<ProvidedService> m_providedServices = new LinkedHashSet<ProvidedService>();
+
+ /**
+ * The handler description.
+ */
+ private ProvidedServiceHandlerDescription m_description;
+
+ /**
+ * Get the array of provided service.
+ * @return the list of the provided service.
+ */
+ public ProvidedService[] getProvidedServices() {
+ return m_providedServices.toArray(new ProvidedService[m_providedServices.size()]);
+ }
+
+ /**
+ * Configure the handler.
+ * @param componentMetadata : the component type metadata
+ * @param configuration : the instance configuration
+ * @throws ConfigurationException : the metadata are not correct.
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element componentMetadata, Dictionary configuration) throws ConfigurationException {
+ m_providedServices.clear();
+ // Create the dependency according to the component metadata
+ Element[] providedServices = componentMetadata.getElements("Provides");
+ for (Element providedService : providedServices) {
+ String[] serviceSpecifications = ParseUtils.parseArrays(providedService.getAttribute("specifications")); // Set by the initialize component factory.
+
+ // Get the factory policy
+ int factory = ProvidedService.SINGLETON_STRATEGY;
+ Class custom = null;
+ String strategy = providedService.getAttribute("strategy");
+ if (strategy == null) {
+ strategy = providedService.getAttribute("factory");
+ }
+ if (strategy != null) {
+ if ("singleton".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.SINGLETON_STRATEGY;
+ } else if ("service".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.SERVICE_STRATEGY;
+ } else if ("method".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.STATIC_STRATEGY;
+ } else if ("instance".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.INSTANCE_STRATEGY;
+ } else {
+ // Customized policy
+ try {
+ custom = getInstanceManager().getContext().getBundle().loadClass(strategy);
+ if (!CreationStrategy.class.isAssignableFrom(custom)) {
+ throw new ConfigurationException("The custom creation policy class " + custom.getName() + " does not implement " + CreationStrategy.class.getName());
+ }
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("The custom creation policy class " + strategy + " cannot be loaded ", e);
+
+ }
+
+ }
+ }
+
+
+ // Then create the provided service
+ ProvidedService svc = new ProvidedService(this, serviceSpecifications, factory, custom, configuration);
+
+ // Post-Registration callback
+ String post = providedService.getAttribute("post-registration");
+ if (post != null) {
+ Callback cb = new Callback(post, new Class[]{ServiceReference.class}, false, getInstanceManager());
+ svc.setPostRegistrationCallback(cb);
+ }
+
+ post = providedService.getAttribute("post-unregistration");
+ if (post != null) {
+ // TODO Can we really send the service reference here ?
+ Callback cb = new Callback(post, new Class[]{ServiceReference.class}, false, getInstanceManager());
+ svc.setPostUnregistrationCallback(cb);
+ }
+
+ Element[] props = providedService.getElements("Property");
+ if (props != null) {
+ //Property[] properties = new Property[props.length];
+ Property[] properties = new Property[props.length];
+ for (int j = 0; j < props.length; j++) {
+ String name = props[j].getAttribute("name");
+ String value = props[j].getAttribute("value");
+ String type = props[j].getAttribute("type");
+ String field = props[j].getAttribute("field");
+
+ Property prop = new Property(name, field, null, value, type, getInstanceManager(), this);
+ properties[j] = prop;
+
+ // Check if the instance configuration has a value for this property
+ Object object = configuration.get(prop.getName());
+ if (object != null) {
+ prop.setValue(object);
+ }
+
+ if (field != null) {
+ getInstanceManager().register(new FieldMetadata(field, type), this);
+ // Cannot register the property as the interception is necessary
+ // to deal with registration update.
+ }
+ }
+
+ // Attach to properties to the provided service
+ svc.setProperties(properties);
+ }
+
+ Element[] controllers = providedService.getElements("Controller");
+ if (controllers != null) {
+ for (Element controller : controllers) {
+ String field = controller.getAttribute("field");
+ if (field == null) {
+ throw new ConfigurationException("The field attribute of a controller is mandatory");
+ }
+
+ String v = controller.getAttribute("value");
+ boolean value = !(v != null && v.equalsIgnoreCase("false"));
+ String s = controller.getAttribute("specification");
+ if (s == null) {
+ s = "ALL";
+ }
+ svc.setController(field, value, s);
+
+ getInstanceManager().register(new FieldMetadata(field, "boolean"), this);
+ }
+ }
+
+ if (checkProvidedService(svc)) {
+ m_providedServices.add(svc);
+ } else {
+ StringBuilder itfs = new StringBuilder();
+ for (String serviceSpecification : serviceSpecifications) {
+ itfs.append(' ');
+ itfs.append(serviceSpecification);
+ }
+ throw new ConfigurationException("The provided service" + itfs + " is not valid");
+ }
+
+ // Initialize the description.
+ m_description = new ProvidedServiceHandlerDescription(this, getProvidedServices());
+
+ }
+ }
+
+ /**
+ * Collect interfaces implemented by the POJO.
+ * @param specs : implemented interfaces.
+ * @param parent : parent class.
+ * @param bundle : Bundle object.
+ * @param interfaces : the set of implemented interfaces
+ * @param classes : the set of extended classes
+ * @throws ClassNotFoundException : occurs when an interface cannot be loaded.
+ */
+ private void computeInterfacesAndSuperClasses(String[] specs, String parent, Bundle bundle,
+ Set<String> interfaces,
+ Set<String> classes) throws ClassNotFoundException {
+ // First iterate on found specification in manipulation metadata
+ for (String spec : specs) {
+ interfaces.add(spec);
+ // Iterate on interfaces implemented by the current interface
+ Class clazz = bundle.loadClass(spec);
+ collectInterfaces(clazz, interfaces, bundle);
+ }
+
+ // Look for parent class.
+ if (parent != null) {
+ Class clazz = bundle.loadClass(parent);
+ collectInterfacesFromClass(clazz, interfaces, bundle);
+ classes.add(parent);
+ collectParentClassesFromClass(clazz, classes, bundle);
+ }
+ }
+
+ /**
+ * Look for inherited interfaces.
+ * @param clazz : interface name to explore (class object)
+ * @param acc : set (accumulator)
+ * @param bundle : bundle
+ * @throws ClassNotFoundException : occurs when an interface cannot be loaded.
+ */
+ private void collectInterfaces(Class clazz, Set<String> acc, Bundle bundle) throws ClassNotFoundException {
+ Class[] clazzes = clazz.getInterfaces();
+ for (Class clazze : clazzes) {
+ acc.add(clazze.getName());
+ collectInterfaces(clazze, acc, bundle);
+ }
+ }
+
+ /**
+ * Collect interfaces for the given class.
+ * This method explores super class to.
+ * @param clazz : class object.
+ * @param acc : set of implemented interface (accumulator)
+ * @param bundle : bundle.
+ * @throws ClassNotFoundException : occurs if an interface cannot be load.
+ */
+ private void collectInterfacesFromClass(Class clazz, Set<String> acc,
+ Bundle bundle) throws ClassNotFoundException {
+ Class[] clazzes = clazz.getInterfaces();
+ for (Class clazze : clazzes) {
+ acc.add(clazze.getName());
+ collectInterfaces(clazze, acc, bundle);
+ }
+ // Iterate on parent classes
+ Class sup = clazz.getSuperclass();
+ if (sup != null) {
+ collectInterfacesFromClass(sup, acc, bundle);
+ }
+ }
+
+ /**
+ * Collect parent classes for the given class.
+ * @param clazz : class object.
+ * @param acc : set of extended classes (accumulator)
+ * @param bundle : bundle.
+ * @throws ClassNotFoundException : occurs if an interface cannot be load.
+ */
+ private void collectParentClassesFromClass(Class clazz, Set<String> acc,
+ Bundle bundle) throws ClassNotFoundException {
+ Class parent = clazz.getSuperclass();
+ if (parent != null) {
+ acc.add(parent.getName());
+ collectParentClassesFromClass(parent, acc, bundle);
+ }
+ }
+
+ /**
+ * Check the provided service given in argument in the sense that the metadata are consistent.
+ * @param svc : the provided service to check.
+ * @return true if the provided service is correct
+ * @throws ConfigurationException : the checked provided service is not correct.
+ */
+ private boolean checkProvidedService(ProvidedService svc) throws ConfigurationException {
+ Set<ClassLoader> classloaders = new LinkedHashSet<ClassLoader>();
+ for (int i = 0; i < svc.getServiceSpecifications().length; i++) {
+ String specName = svc.getServiceSpecifications()[i];
+
+ // Check service level dependencies
+ try {
+ Class spec = load(specName, classloaders);
+ classloaders.add(spec.getClassLoader());
+ Field specField = spec.getField("specification");
+ Object specif = specField.get(null);
+ if (specif instanceof String) {
+ Element specification = ManifestMetadataParser.parse((String) specif);
+ Element[] deps = specification.getElements("requires");
+ for (int j = 0; deps != null && j < deps.length; j++) {
+ Dependency dep = getAttachedDependency(deps[j]);
+ if (dep != null) {
+ // Fix service-level dependency flag
+ dep.setServiceLevelDependency();
+ }
+ isDependencyCorrect(dep, deps[j]);
+ }
+ } else {
+ throw new ConfigurationException("Service Providing: The specification field of the service specification " + svc.getServiceSpecifications()[i] + " needs to be a String");
+ }
+ } catch (NoSuchFieldException e) {
+ // Ignore it, keep and going.
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Service Providing: The service specification " + svc.getServiceSpecifications()[i] + " cannot be loaded", e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Service Providing: The field 'specification' of the service specification " + svc.getServiceSpecifications()[i] + " is not accessible", e);
+ } catch (IllegalAccessException e) {
+ throw new ConfigurationException("Service Providing: The field 'specification' of the service specification " + svc.getServiceSpecifications()[i] + " is not accessible", e);
+ } catch (ParseException e) {
+ throw new ConfigurationException("Service Providing: The field 'specification' of the service specification " + svc.getServiceSpecifications()[i] + " does not contain a valid String", e);
+ }
+ }
+
+ return true;
+ }
+
+ private Class load(String specName, Set<ClassLoader> classloaders) throws ClassNotFoundException {
+ try {
+ return getInstanceManager().getFactory().loadClass(specName);
+ } catch (ClassNotFoundException e) {
+ // Try collected classloaders.
+ }
+ for (ClassLoader cl : classloaders) {
+ try {
+ return cl.loadClass(specName);
+ } catch (ClassNotFoundException e) {
+ // Try next one.
+ }
+ }
+ throw new ClassNotFoundException(specName);
+ }
+
+ /**
+ * Look for the implementation (i.e. component) dependency for the given service-level requirement metadata.
+ * @param element : the service-level requirement metadata
+ * @return the Dependency object, null if not found or if the DependencyHandler is not plugged to the instance
+ */
+ private Dependency getAttachedDependency(Element element) {
+ DependencyHandler handler = (DependencyHandler) getHandler(HandlerFactory.IPOJO_NAMESPACE + ":requires");
+ if (handler == null) { return null; }
+
+ String identity = element.getAttribute("id");
+ if (identity != null) {
+ // Look for dependency Id
+ for (int i = 0; i < handler.getDependencies().length; i++) {
+ if (handler.getDependencies()[i].getId().equals(identity)) { return handler.getDependencies()[i]; }
+ }
+ }
+ // If not found or no id, look for a dependency with the same specification
+ String requirement = element.getAttribute("specification");
+ for (int i = 0; i < handler.getDependencies().length; i++) {
+ if ((handler.getDependencies()[i].getSpecification().getName()).equals(requirement)) { return handler.getDependencies()[i]; }
+ }
+
+ return null;
+ }
+
+ /**
+ * Check the correctness of the implementation dependency against the service level dependency.
+ * @param dep : dependency to check
+ * @param elem : service-level dependency metadata
+ * @throws ConfigurationException : the service level dependency and the implementation dependency does not match.
+ */
+ private void isDependencyCorrect(Dependency dep, Element elem) throws ConfigurationException {
+ String optional = elem.getAttribute("optional");
+ boolean opt = optional != null && optional.equalsIgnoreCase("true");
+
+ String aggregate = elem.getAttribute("aggregate");
+ boolean agg = aggregate != null && aggregate.equalsIgnoreCase("true");
+
+ if (dep == null && !opt) {
+ throw new ConfigurationException("Service Providing: The requirement " + elem.getAttribute("specification") + " is not present in the implementation and is declared as a mandatory service-level requirement");
+ }
+
+ if (dep != null && dep.isAggregate() && !agg) {
+ throw new ConfigurationException("Service Providing: The requirement " + elem.getAttribute("specification") + " is aggregate in the implementation and is declared as a simple service-level requirement");
+ }
+
+ String filter = elem.getAttribute("filter");
+ if (dep != null && filter != null) {
+ String filter2 = dep.getFilter();
+ if (filter2 == null || !filter2.equalsIgnoreCase(filter)) {
+ throw new ConfigurationException("Service Providing: The specification requirement " + elem.getAttribute("specification") + " has not the same filter as declared in the service-level requirement");
+ }
+ }
+ }
+
+ /**
+ * Stop the provided service handler.
+ *
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ //Nothing to do.
+ }
+
+ /**
+ * Start the provided service handler.
+ *
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Nothing to do.
+ }
+
+ /**
+ * Setter Callback Method.
+ * Check if the modified field is a property to update the value.
+ * @param pojo : the pojo object on which the field is accessed
+ * @param fieldName : field name
+ * @param value : new value
+ * @see org.apache.felix.ipojo.FieldInterceptor#onSet(Object, String, Object)
+ */
+ public void onSet(Object pojo, String fieldName, Object value) {
+ // Verify that the field name correspond to a dependency
+ for (ProvidedService svc : m_providedServices) {
+ boolean update = false;
+ // Retrieve a copy of the properties.
+ final Property[] properties = svc.getProperties();
+ for (Property prop : properties) {
+ if (fieldName.equals(prop.getField()) && !prop.getValue().equals(value)) {
+ // it is the associated property
+ prop.setValue(value);
+ update = true;
+ }
+ }
+ if (update) {
+ svc.update();
+ }
+ ServiceController ctrl = svc.getController(fieldName);
+ if (ctrl != null) {
+ if (value instanceof Boolean) {
+ ctrl.setValue((Boolean) value);
+ } else {
+ warn("Boolean value expected for the service controller " + fieldName);
+ }
+ }
+ }
+ // Else do nothing
+ }
+
+ /**
+ * Getter Callback Method.
+ * Check if the field is a property to push the stored value.
+ * @param pojo : the pojo object on which the field is accessed
+ * @param fieldName : field name
+ * @param value : value pushed by the previous handler
+ * @return the stored value or the previous value.
+ * @see org.apache.felix.ipojo.FieldInterceptor#onGet(Object, String, Object)
+ */
+ public Object onGet(Object pojo, String fieldName, Object value) {
+ for (ProvidedService svc : m_providedServices) {
+ for (int j = 0; j < svc.getProperties().length; j++) {
+ Property prop = svc.getProperties()[j];
+ if (fieldName.equals(prop.getField())) {
+ // Manage the No Value case.
+ return prop.onGet(pojo, fieldName, value);
+ }
+ }
+ ServiceController ctrl = svc.getController(fieldName);
+ if (ctrl != null) {
+ return ctrl.getValue();
+ }
+ }
+ // Else it is not a property
+ return value;
+ }
+
+ /**
+ * Register the services if the new state is VALID. Un-register the services
+ * if the new state is UNRESOLVED.
+ *
+ * @param state : the new instance state.
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ // If the new state is INVALID => un-register all the services
+ if (state == InstanceManager.INVALID) {
+ for (ProvidedService m_providedService : m_providedServices) {
+ m_providedService.unregisterService();
+ }
+ return;
+ }
+
+ // If the new state is VALID => register all the services
+ if (state == InstanceManager.VALID) {
+ for (ProvidedService ps : m_providedServices) {
+ ps.registerService();
+ }
+ }
+
+ // If the new state is DISPOSED => cleanup all the provided services listeners
+ if (state == InstanceManager.DISPOSED) {
+ for (ProvidedService ps : m_providedServices) {
+ ps.cleanup();
+ }
+ }
+ }
+
+ /**
+ * Adds properties to all provided services.
+ * @param dict : dictionary of properties to add
+ */
+ public void addProperties(Dictionary dict) {
+ for (ProvidedService ps : m_providedServices) {
+ ps.addProperties(dict);
+ ps.update();
+ }
+ }
+
+ /**
+ * Remove properties form all provided services.
+ *
+ * @param dict : dictionary of properties to delete.
+ */
+ public void removeProperties(Dictionary dict) {
+ for (ProvidedService ps : m_providedServices) {
+ ps.deleteProperties(dict);
+ ps.update();
+ }
+ }
+
+ /**
+ * Build the provided service description.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.Handler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return m_description;
+ }
+
+ /**
+ * Reconfigure provided service.
+ * @param dict : the new instance configuration.
+ * @see org.apache.felix.ipojo.Handler#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary dict) {
+ for (int j = 0; j < getProvidedServices().length; j++) {
+ ProvidedService svc = getProvidedServices()[j];
+ Property[] props = svc.getProperties();
+ boolean update = false;
+ for (Property prop : props) {
+ final Object receivedValue = dict.get(prop.getName());
+ if (receivedValue != null) {
+ update = true;
+ prop.setValue(receivedValue);
+ }
+ }
+ if (update) {
+ svc.update();
+ }
+ }
+ }
+
+ /**
+ * Initialize the component type.
+ * @param desc : component type description to populate.
+ * @param metadata : component type metadata.
+ * @throws ConfigurationException : occurs when the POJO does not implement any interfaces.
+ * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentTypeDescription, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void initializeComponentFactory(ComponentTypeDescription desc, Element metadata) throws ConfigurationException {
+ // Change ComponentInfo
+ Element[] provides = metadata.getElements("provides");
+ PojoMetadata manipulation = getFactory().getPojoMetadata();
+
+ for (Element provide : provides) {
+ // First : create the serviceSpecification list
+ String[] serviceSpecification = manipulation.getInterfaces();
+ String parent = manipulation.getSuperClass();
+ Set<String> interfaces = new HashSet<String>();
+ Set<String> parentClasses = new HashSet<String>();
+ try {
+ computeInterfacesAndSuperClasses(serviceSpecification, parent, desc.getBundleContext().getBundle(), interfaces, parentClasses);
+ getLogger().log(Logger.INFO, "Collected interfaces from " + metadata.getAttribute("classname") + " : " + interfaces);
+ getLogger().log(Logger.INFO, "Collected super classes from " + metadata.getAttribute("classname") + " : " + parentClasses);
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("An interface or parent class cannot be loaded", e);
+ }
+
+ String serviceSpecificationStr = provide.getAttribute("specifications");
+ if (serviceSpecificationStr == null) {
+ serviceSpecificationStr = provide.getAttribute("interface");
+ if (serviceSpecificationStr != null) {
+ warn("The 'interface' attribute is deprecated, use the 'specifications' attribute instead of 'interface'");
+ }
+ }
+
+ if (serviceSpecificationStr != null) {
+ List<String> itfs = ParseUtils.parseArraysAsList(serviceSpecificationStr);
+ for (String itf : itfs)
+ if (!interfaces.contains(itf)
+ && !parentClasses.contains(itf)
+ && !desc.getFactory().getClassName().equals(itf)) {
+ desc.getFactory().getLogger().log(Logger.ERROR, "The specification " + itf + " is not implemented by " + metadata.getAttribute("classname"));
+ }
+ interfaces.clear();
+ interfaces.addAll(itfs);
+ }
+
+ if (interfaces.isEmpty()) {
+ warn("No service interface found in the class hierarchy, use the implementation class");
+ interfaces.add(desc.getFactory().getClassName());
+ }
+
+ StringBuffer specs = null;
+ Set<String> set = new HashSet<String>(interfaces);
+ set.remove(Pojo.class.getName()); // Remove POJO.
+ for (String spec : set) {
+ desc.addProvidedServiceSpecification(spec);
+ if (specs == null) {
+ specs = new StringBuffer("{");
+ specs.append(spec);
+ } else {
+ specs.append(',');
+ specs.append(spec);
+ }
+ }
+
+ specs.append('}');
+ provide.addAttribute(new Attribute("specifications", specs.toString())); // Add interface attribute to avoid checking in the configure method
+
+ Element[] props = provide.getElements("property");
+ for (int j = 0; props != null && j < props.length; j++) {
+ String name = props[j].getAttribute("name");
+ String value = props[j].getAttribute("value");
+ String type = props[j].getAttribute("type");
+ String field = props[j].getAttribute("field");
+
+
+ // Get property name :
+ if (field != null && name == null) {
+ name = field;
+ }
+
+ // Check type if not already set
+ if (type == null) {
+ if (field == null) {
+ throw new ConfigurationException("The property " + name + " has neither type nor field.");
+ }
+ FieldMetadata fieldMeta = manipulation.getField(field);
+ if (fieldMeta == null) {
+ throw new ConfigurationException("A declared property was not found in the implementation class : " + field);
+ }
+ type = fieldMeta.getFieldType();
+ props[j].addAttribute(new Attribute("type", type));
+ }
+
+ // Is the property set to immutable
+ boolean immutable = false;
+ String imm = props[j].getAttribute("immutable");
+ if (imm != null && imm.equalsIgnoreCase("true")) {
+ immutable = true;
+ }
+
+ PropertyDescription pd = new PropertyDescription(name, type, value, immutable);
+ desc.addProperty(pd);
+
+ String man = props[j].getAttribute("mandatory");
+ if (man != null && man.equalsIgnoreCase("true")) {
+ pd.setMandatory();
+ }
+ }
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerDescription.java
new file mode 100644
index 0000000..fa080f9
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerDescription.java
@@ -0,0 +1,119 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.Constants;
+
+/**
+ * Provided Service Handler Description.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandlerDescription extends HandlerDescription {
+
+ /**
+ * Provided Service Description list.
+ */
+ private ProvidedServiceDescription[] m_providedServices = new ProvidedServiceDescription[0];
+
+ /**
+ * Constructor.
+ * @param handler the handler.
+ * @param pss the list of provided service
+ */
+ public ProvidedServiceHandlerDescription(ProvidedServiceHandler handler, ProvidedService[] pss) {
+ super(handler);
+ m_providedServices = new ProvidedServiceDescription[pss.length];
+ for (int i = 0; i < pss.length; i++) {
+ m_providedServices[i] = new ProvidedServiceDescription(pss[i]);
+ }
+ }
+
+ /**
+ * Get the provided service descriptions.
+ * @return the provided service description list.
+ */
+ public ProvidedServiceDescription[] getProvidedServices() {
+ return m_providedServices;
+ }
+
+ /**
+ * Build the provided service handler description.
+ * @return the handler description.
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element services = super.getHandlerInfo();
+ for (int i = 0; i < m_providedServices.length; i++) {
+ Element service = new Element("provides", null);
+ StringBuffer spec = new StringBuffer("[");
+ for (int j = 0; j < m_providedServices[i].getServiceSpecifications().length; j++) {
+ if (j == 0) {
+ spec.append(m_providedServices[i].getServiceSpecifications()[j]);
+ } else {
+ spec.append(',');
+ spec.append(m_providedServices[i].getServiceSpecifications()[j]);
+ }
+ }
+ spec.append(']');
+ service.addAttribute(new Attribute("specifications", spec.toString()));
+
+ if (m_providedServices[i].getState() == ProvidedService.REGISTERED) {
+ service.addAttribute(new Attribute("state", "registered"));
+ service.addAttribute(new Attribute("service.id", m_providedServices[i].getServiceReference()
+ .getProperty(Constants.SERVICE_ID).toString()));
+ } else {
+ service.addAttribute(new Attribute("state", "unregistered"));
+ }
+
+ // Service Properties.
+ Properties props = m_providedServices[i].getProperties();
+ Iterator iterator = props.keySet().iterator();
+ while (iterator.hasNext()) {
+ Element prop = new Element("property", null);
+ String name = (String) iterator.next();
+ prop.addAttribute(new Attribute("name", name));
+ Object obj = props.get(name);
+ if (obj != null) {
+ prop.addAttribute(new Attribute("value", obj.toString()));
+ } else {
+ prop.addAttribute(new Attribute("value", "null"));
+ }
+ service.addElement(prop);
+ }
+
+ // Service Controller.
+ if (m_providedServices[i].getController() != null) {
+ Element controller = new Element("controller", null);
+ controller.addAttribute(new Attribute("value", m_providedServices[i].getController()));
+ service.addElement(controller);
+ }
+
+ services.addElement(service);
+ }
+ return services;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceListener.java
new file mode 100644
index 0000000..c32f1ba
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceListener.java
@@ -0,0 +1,52 @@
+/*
+ * 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.handlers.providedservice;
+
+import org.apache.felix.ipojo.ComponentInstance;
+
+/**
+ * Listener interface for services provided by iPOJO component instances.
+ */
+public interface ProvidedServiceListener {
+
+ /**
+ * Called when the service has been registered.
+ *
+ * @param instance the concerned component instance
+ * @param providedService the registered service
+ */
+ void serviceRegistered(ComponentInstance instance, ProvidedService providedService);
+
+ /**
+ * Called when the registered service has been updated.
+ *
+ * @param instance the concerned component instance
+ * @param providedService the updated service
+ */
+ void serviceModified(ComponentInstance instance, ProvidedService providedService);
+
+ /**
+ * Called when the service is unregistered.
+ *
+ * @param instance the concerned component instance
+ * @param providedService the unregistered service
+ */
+ void serviceUnregistered(ComponentInstance instance, ProvidedService providedService);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ConfigurableCreationStrategy.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ConfigurableCreationStrategy.java
new file mode 100644
index 0000000..5c5ed35
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ConfigurableCreationStrategy.java
@@ -0,0 +1,142 @@
+/*
+ * 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.handlers.providedservice.strategy;
+
+import java.lang.reflect.Proxy;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.handlers.providedservice.CreationStrategy;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This {@link CreationStrategy} is here to ease customization of the strategy
+ * by hiding all the reflection stuff.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class ConfigurableCreationStrategy extends CreationStrategy {
+
+ /**
+ * The instance manager passed to the iPOJO ServiceFactory to manage
+ * instances.
+ */
+ private InstanceManager m_manager;
+
+ /**
+ * The lists of interfaces provided by this service.
+ */
+ private String[] m_specs;
+
+ /**
+ * The iPOJO ServiceFactory.
+ */
+ private IPOJOServiceFactory m_factory;
+
+ /**
+ * Method called when the underlying iPOJO Service factory
+ * is published.
+ * @param manager the instance manager
+ * @param specifications the provided specifications
+ * @param props the service properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(org.apache.felix.ipojo.InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(final InstanceManager manager,
+ final String[] specifications, final Properties props) {
+ // Store specifications (aka interfaces)
+ this.m_specs = specifications;
+ this.m_manager = manager;
+ }
+
+ /**
+ * Method called when the underlying iPOJO Service factory is
+ * un-published.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ // Try to close the factory
+ if (m_factory instanceof ServiceObjectFactory) {
+ ((ServiceObjectFactory) m_factory).close();
+ }
+ }
+
+ /**
+ * Method called when a bundle want to access a service. This method is called once per
+ * asking bundle. To turn around this limitation, a proxy is registered.
+ * @param bundle the asking bundle
+ * @param registration the service registration
+ * @return the service object
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(final Bundle bundle,
+ final ServiceRegistration registration) {
+ // Init the factory if needed
+ if (m_factory == null) {
+ m_factory = getServiceFactory(m_manager);
+ }
+ // Return a proxy wrapping the real iPOJO ServiceFactory
+ return Proxy.newProxyInstance(m_manager.getClazz().getClassLoader(),
+ getModifiedSpecifications(m_manager.getContext()),
+ new ErrorPrintingServiceFactoryProxy(m_factory));
+ }
+
+ /**
+ * Method called when a bundle release a service.
+ * @param bundle the bundle
+ * @param registration the service registration
+ * @param service the service object
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(final Bundle bundle,
+ final ServiceRegistration registration, final Object service) {
+ // Nothing to do
+ }
+
+ /**
+ * Utility method that transform the specifications names into a Class
+ * array, appending the IPOJOServiceFactory interface to it.
+ * @param context used for class loading
+ * @return a array of Class
+ */
+ private Class[] getModifiedSpecifications(final BundleContext context) {
+ Class[] classes = new Class[m_specs.length + 1];
+ int i = 0;
+ for (i = 0; i < m_specs.length; i++) {
+ try {
+ classes[i] = context.getBundle().loadClass(m_specs[i]);
+ } catch (ClassNotFoundException e) {
+ // Should not happen.
+ }
+ }
+ classes[i] = IPOJOServiceFactory.class;
+ return classes;
+ }
+
+ /**
+ * User provided {@link CreationStrategy} MUST implement this method to
+ * provide the real iPOJO ServiceFactory instance.
+ * @param manager {@link InstanceManager} that the factory could use
+ * @return an instance of {@link IPOJOServiceFactory}
+ */
+ protected abstract IPOJOServiceFactory getServiceFactory(
+ final InstanceManager manager);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ErrorPrintingServiceFactoryProxy.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ErrorPrintingServiceFactoryProxy.java
new file mode 100644
index 0000000..5886236
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ErrorPrintingServiceFactoryProxy.java
@@ -0,0 +1,109 @@
+/*
+ * 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.handlers.providedservice.strategy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+
+/**
+ * This proxy class is here to wrap an iPOJO ServiceFactory.
+ * If the consumer of this service do not call the getService or ungetService
+ * methods, it will get an Exception with an explicit error message telling
+ * him that this service is only usable through iPOJO.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ErrorPrintingServiceFactoryProxy implements InvocationHandler {
+
+ /**
+ * getService(ComponentInstance) method.
+ */
+ private static Method GET_METHOD;
+
+ /**
+ * ungetService(ComponentInstance, Object) method.
+ */
+ private static Method UNGET_METHOD;
+
+ /**
+ * Wrapped factory.
+ */
+ private final IPOJOServiceFactory m_factory;
+
+ static {
+ // Static initialization of theses constants.
+ try {
+ GET_METHOD = IPOJOServiceFactory.class.getMethod("getService",
+ new Class[]{ComponentInstance.class});
+ UNGET_METHOD = IPOJOServiceFactory.class.getMethod("ungetService",
+ new Class[]{ComponentInstance.class, Object.class});
+ } catch (Exception e) {
+ // Should never happen
+ }
+ }
+
+ /**
+ * Wraps a ServiceFactory in an InvocationHandler that will delegate only
+ * get/ungetService methods to the factory. All other methods will be
+ * rejected with a meaningful error message.
+ *
+ * @param factory delegating iPOJO ServiceFactory
+ */
+ public ErrorPrintingServiceFactoryProxy(final IPOJOServiceFactory factory) {
+ this.m_factory = factory;
+ }
+
+ /**
+ * 'Invoke' methods called when a method is called on the proxy.
+ * @param proxy the proxy
+ * @param method the method
+ * @param args the arguments
+ * @return the result
+ * @throws Exception if something wrong happens
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(final Object proxy,
+ final Method method,
+ final Object[] args) throws Exception {
+
+ // Handle get/unget operations
+ if (GET_METHOD.equals(method)) {
+ return m_factory.getService((ComponentInstance) args[0]);
+ }
+ if (UNGET_METHOD.equals(method)) {
+ m_factory.ungetService((ComponentInstance) args[0], args[1]);
+ return null;
+ }
+
+ // KF is calling hashCode, we return the proxy hashCode.
+ if (method.getName().equals("hashCode")) {
+ return this.hashCode();
+ }
+
+ // All other methods are rejected
+ throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ + "Before calling the service, call the IPOJOServiceFactory.getService(ComponentInstance) "
+ + "method to get the service object. ");
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ServiceObjectFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ServiceObjectFactory.java
new file mode 100644
index 0000000..26c4fc7
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/strategy/ServiceObjectFactory.java
@@ -0,0 +1,36 @@
+/*
+ * 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.handlers.providedservice.strategy;
+
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+
+/**
+ * Extended iPOJOServiceFactory that supports a close() operation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceObjectFactory extends IPOJOServiceFactory {
+
+ /**
+ * Called when the supporting CreationStrategy is unpublished
+ * from the service registry. This allows to do an explicit
+ * cleanup.
+ */
+ void close();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java
new file mode 100644
index 0000000..db8bc98
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/FieldMetadata.java
@@ -0,0 +1,159 @@
+/*
+ * 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.parser;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A Field Metadata represents a field of the implementation class.
+ * This class avoids using reflection to get the type and the name of a field.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadata {
+
+ /**
+ * The name of the field.
+ */
+ private String m_name;
+
+ /**
+ * The yype of the field.
+ */
+ private String m_type;
+
+ /**
+ * Creates a field metadata.
+ * This constructor is used when creating the {@link PojoMetadata}
+ * object.
+ * @param metadata the field manipulation element from Manipulation
+ * Metadata.
+ */
+ FieldMetadata(Element metadata) {
+ m_name = metadata.getAttribute("name");
+ m_type = metadata.getAttribute("type");
+ }
+
+ /**
+ * Creates a field metadata.
+ * This constructor can be used to avoid using {@link PojoMetadata}.
+ * Be care that creating such {@link FieldMetadata} does not assert its
+ * presence in the implementation class.
+ * @param field the field name.
+ * @param type the type of the field.
+ */
+ public FieldMetadata(String field, String type) {
+ m_name = field;
+ m_type = type;
+ }
+
+ public String getFieldName() { return m_name; }
+
+ public String getFieldType() { return m_type; }
+
+ /**
+ * Gets the 'reflective' type of the given type.
+ * The reflective type is the type used by the Java Reflection API.
+ * More precisely this method handles the array cases
+ * @param type the type to analyze to find the Java reflective type.
+ * @return the reflective type corresponding to this field.
+ */
+ public static String getReflectionType(String type) {
+ // Primitive Array
+ if (type.endsWith("[]") && type.indexOf('.') == -1) {
+ int index = type.indexOf('[');
+ return '[' + getInternalPrimitiveType(type.substring(0, index));
+ }
+ // Non-Primitive Array
+ if (type.endsWith("[]") && type.indexOf('.') != -1) {
+ int index = type.indexOf('[');
+ return "[L" + type.substring(0, index) + ";";
+ }
+ // The type is not an array.
+ return type;
+ }
+
+ /**
+ * Gets the internal notation for primitive type.
+ * @param string the String form of the type
+ * @return the internal notation or <code>null</code> if not found
+ */
+ public static String getInternalPrimitiveType(String string) {
+ if (string.equalsIgnoreCase("boolean")) {
+ return "Z";
+ }
+ if (string.equalsIgnoreCase("char")) {
+ return "C";
+ }
+ if (string.equalsIgnoreCase("byte")) {
+ return "B";
+ }
+ if (string.equalsIgnoreCase("short")) {
+ return "S";
+ }
+ if (string.equalsIgnoreCase("int")) {
+ return "I";
+ }
+ if (string.equalsIgnoreCase("float")) {
+ return "F";
+ }
+ if (string.equalsIgnoreCase("long")) {
+ return "J";
+ }
+ if (string.equalsIgnoreCase("double")) {
+ return "D";
+ }
+ return null;
+ }
+
+ /**
+ * Gets the iPOJO primitive type from the given primitive class.
+ * @param clazz the class of the primitive type
+ * @return the iPOJO primitive type name or <code>null</code> if
+ * not found.
+ */
+ public static String getPrimitiveTypeByClass(Class clazz) {
+ if (clazz.equals(Boolean.TYPE)) {
+ return "boolean";
+ }
+ if (clazz.equals(Character.TYPE)) {
+ return "char";
+ }
+ if (clazz.equals(Byte.TYPE)) {
+ return "byte";
+ }
+ if (clazz.equals(Short.TYPE)) {
+ return "short";
+ }
+ if (clazz.equals(Integer.TYPE)) {
+ return "int";
+ }
+ if (clazz.equals(Float.TYPE)) {
+ return "float";
+ }
+ if (clazz.equals(Long.TYPE)) {
+ return "long";
+ }
+ if (clazz.equals(Double.TYPE)) {
+ return "double";
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
new file mode 100644
index 0000000..e5bd89e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
@@ -0,0 +1,561 @@
+/*
+ * 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.parser;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * The Manifest Metadata parser reads a manifest file and builds
+ * the iPOJO metadata ({@link Element} / {@link Attribute} ) structure.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManifestMetadataParser {
+
+ /**
+ * The element list.
+ * Contains the element found in the parsed header.
+ */
+ private Element[] m_elements = new Element[0];
+
+ /**
+ * Gets the array of component type metadata.
+ * @return the component metadata (composite & component).
+ * An empty array is returned if no component type declaration.
+ * @throws ParseException if a parsing error occurs
+ */
+ public Element[] getComponentsMetadata() throws ParseException {
+ Element[] elems = m_elements[0].getElements();
+ List list = new ArrayList();
+ for (int i = 0; i < elems.length; i++) {
+ if (!"instance".equals(elems[i].getName())) {
+ list.add(elems[i]);
+ }
+ }
+ return (Element[]) list.toArray(new Element[list.size()]);
+ }
+
+ /**
+ * Gets the array of instance configuration described in the metadata.
+ * @return the instances list or <code>null</code> if no instance configuration.
+ * @throws ParseException if the metadata cannot be parsed successfully
+ */
+ public Dictionary[] getInstances() throws ParseException {
+ Element[] configs = m_elements[0].getElements("instance");
+ if (configs == null) {
+ return null;
+ }
+ Dictionary[] dicts = new Dictionary[configs.length];
+ for (int i = 0; i < configs.length; i++) {
+ dicts[i] = parseInstance(configs[i]);
+ }
+ return dicts;
+ }
+
+ /**
+ * Parses an Element to create an instance configuration dictionary.
+ * The 'name' attribute of the instance declaration is mapped
+ * to the 'instance.name' property.
+ * @param instance the Element describing an instance.
+ * @return the resulting dictionary
+ * @throws ParseException if a configuration cannot be parse correctly.
+ */
+ private Dictionary parseInstance(Element instance) throws ParseException {
+ Dictionary dict = new Properties();
+ String name = instance.getAttribute("name");
+ String comp = instance.getAttribute("component");
+ String version = instance.getAttribute("version");
+
+ if (name != null) {
+ dict.put(Factory.INSTANCE_NAME_PROPERTY, instance.getAttribute("name"));
+ }
+
+ if (comp == null) {
+ throw new ParseException("An instance does not have the 'component' attribute");
+ }
+
+ dict.put("component", comp);
+
+ if (version != null) {
+ dict.put(Factory.FACTORY_VERSION_PROPERTY, version);
+ }
+
+ Element[] props = instance.getElements("property");
+
+ for (int i = 0; props != null && i < props.length; i++) {
+ parseProperty(props[i], dict);
+ }
+
+ return dict;
+ }
+
+ /**
+ * Parses an instance property.
+ * This method is recursive to handle complex properties.
+ * @param prop the current element to parse
+ * @param dict the dictionary to populate (the future instance configuration)
+ * @throws ParseException if the property cannot be parsed correctly
+ */
+ private void parseProperty(Element prop, Dictionary dict) throws ParseException {
+ // Check that the property has a name
+ String name = prop.getAttribute("name");
+ String value = prop.getAttribute("value");
+ if (name == null) {
+ throw new ParseException("A property does not have the 'name' attribute: " + prop);
+ }
+
+ //case : the property element has no 'value' attribute
+ if (value == null) {
+ // Recursive case
+ // Get the type of the structure to create
+ String type = prop.getAttribute("type");
+ if (type == null || type.equalsIgnoreCase("dictionary")) {
+ dict.put(name, parseDictionary(prop));
+ } else if (type.equalsIgnoreCase("map")) {
+ dict.put(name, parseMap(prop));
+ } else if (type.equalsIgnoreCase("list")) {
+ dict.put(name, parseList(prop));
+ } else if (type.equalsIgnoreCase("array")) {
+ List list = parseList(prop);
+ boolean isString = true;
+ for (int i = 0; isString && i < list.size(); i++) {
+ isString = list.get(i) instanceof String;
+ }
+ Object[] obj = null;
+ if (isString) {
+ obj = new String[list.size()];
+ } else {
+ obj = new Object[list.size()];
+ }
+ // Transform the list to array
+ dict.put(name, list.toArray(obj));
+ }
+ } else {
+ dict.put(prop.getAttribute("name"), prop.getAttribute("value"));
+ }
+ }
+
+ /**
+ * Parses a complex property.
+ * This property will be built as a {@link Dictionary}.
+ * @param prop the Element to parse.
+ * @return the resulting dictionary
+ * @throws ParseException if an internal property is incorrect.
+ */
+ private Dictionary parseDictionary(Element prop) throws ParseException {
+ // Check if there is 'property' elements
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ Dictionary dict2 = new Properties();
+ for (int i = 0; i < subProps.length; i++) {
+ parseProperty(subProps[i], dict2);
+ }
+ return dict2;
+ } else {
+ // If the no sub-properties, inject an empty dictionary.
+ return new Properties();
+ }
+ }
+
+ /**
+ * Parses a complex property.
+ * This property will be built as a {@link Map}.
+ * The used {@link Map} implementation is {@link HashMap}.
+ * @param prop the property to parse
+ * @return the resulting Map
+ * @throws ParseException if an internal property is incorrect.
+ */
+ private Map parseMap(Element prop) throws ParseException {
+ // Check if there is 'property' elements
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ Map map = new HashMap(); // Create an hashmap to store elements.
+ for (int i = 0; i < subProps.length; i++) {
+ parseProperty(subProps[i], map);
+ }
+ return map;
+ } else { // if not inject an empty map
+ return new HashMap(0);
+ }
+ }
+
+ /**
+ * Parses a complex property. This property will be built as a {@link List}.
+ * The used {@link List} implementation is {@link ArrayList}.
+ * The order of elements is kept.
+ * @param prop the property to parse
+ * @return the resulting List
+ * @throws ParseException if an internal property is incorrect.
+ */
+ private List parseList(Element prop) throws ParseException {
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ List list = new ArrayList(subProps.length); // Create a list to store elements.
+ for (int i = 0; i < subProps.length; i++) {
+ parseAnonymousProperty(subProps[i], list); // Anonymous properties.
+ }
+ return list;
+ } else {
+ // If no sub-properties, inject an empty list.
+ return new ArrayList(0);
+ }
+ }
+
+ /**
+ * Parse a property.
+ * This methods handles complex properties.
+ * @param prop the current element to parse
+ * @param map the map to populate
+ * @throws ParseException if the property cannot be parsed correctly
+ */
+ private void parseProperty(Element prop, Map map) throws ParseException {
+ // Check that the property has a name
+ String name = prop.getAttribute("name");
+ String value = prop.getAttribute("value");
+ if (name == null) {
+ throw new ParseException(
+ "A property does not have the 'name' attribute");
+ }
+ // case : the property element has no 'value' attribute
+ if (value == null) {
+ // Recursive case
+ // Get the type of the structure to create
+ String type = prop.getAttribute("type");
+ if (type == null || type.equalsIgnoreCase("dictionary")) {
+ map.put(name, parseDictionary(prop));
+ } else if (type.equalsIgnoreCase("map")) {
+ map.put(name, parseMap(prop));
+ } else if (type.equalsIgnoreCase("list")) {
+ map.put(name, parseList(prop));
+ } else if (type.equalsIgnoreCase("array")) {
+ List list = parseList(prop);
+ boolean isString = true;
+ for (int i = 0; isString && i < list.size(); i++) {
+ isString = list.get(i) instanceof String;
+ }
+ Object[] obj = null;
+ if (isString) {
+ obj = new String[list.size()];
+ } else {
+ obj = new Object[list.size()];
+ }
+ map.put(name, list.toArray(obj)); // Transform the list to array
+ }
+ } else {
+ map.put(prop.getAttribute("name"), prop.getAttribute("value"));
+ }
+ }
+
+ /**
+ * Parse an anonymous property.
+ * An anonymous property is a property with no name.
+ * An anonymous property can be simple (just a value) or complex (i.e. a map, a dictionary
+ * a list or an array).
+ * @param prop the property to parse
+ * @param list the list to populate with the resulting property
+ * @throws ParseException if an internal property cannot be parse correctly
+ */
+ private void parseAnonymousProperty(Element prop, List list) throws ParseException {
+ // Check that the property has a name
+ String name = prop.getAttribute("name");
+ String value = prop.getAttribute("value");
+ if (name != null) {
+ throw new ParseException("Anonymous property expected in a list or an array");
+ }
+ //case : the property element has no 'value' attribute
+ if (value == null) {
+ // Recursive case
+
+ // Get the type of the structure to create
+ String type = prop.getAttribute("type");
+ if (type == null || type.equalsIgnoreCase("dictionary")) {
+ // Check if there is 'property' elements
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ Dictionary dict2 = new Properties();
+ for (int i = 0; i < subProps.length; i++) {
+ parseProperty(subProps[i], dict2);
+ }
+ list.add(dict2);
+ } else {
+ // If the no sub-properties, inject an empty dictionary.
+ list.add(new Properties());
+ }
+ } else if (type.equalsIgnoreCase("map")) {
+ // Check if there is 'property' elements
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ Map map2 = new HashMap(); // Create an hashmap to store elements.
+ for (int i = 0; i < subProps.length; i++) {
+ parseProperty(subProps[i], map2);
+ }
+ list.add(map2);
+ } else { // if not inject an empty map
+ list.add(new HashMap(0));
+ }
+ } else if (type.equalsIgnoreCase("list")) {
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ // Create a list to store elements.
+ List list2 = new ArrayList(subProps.length);
+ for (int i = 0; i < subProps.length; i++) {
+ parseAnonymousProperty(subProps[i], list2); // Anonymous properties
+ }
+ list.add(list2);
+ } else {
+ // If no sub-properties, inject an empty list.
+ list.add(new ArrayList(0));
+ }
+ } else if (type.equalsIgnoreCase("array")) {
+ // Check sub-props.
+ Element[] subProps = prop.getElements("property");
+ if (subProps != null) {
+ List list2 = new ArrayList(subProps.length); // Use list as
+ // pivot type
+ for (int i = 0; i < subProps.length; i++) {
+ parseAnonymousProperty(subProps[i], list2);
+ }
+ list.add(list.toArray(new Object[list.size()])); // Transform
+ // the list
+ // to array
+ } else {
+ list.add(new Element[0]); // Insert an empty Element array.
+ }
+ }
+ } else {
+ list.add(prop.getAttribute("value"));
+ }
+
+ }
+
+ /**
+ * Adds an element to the {@link ManifestMetadataParser#m_elements} list.
+ * @param elem the the element to add
+ */
+ private void addElement(Element elem) {
+ if (m_elements == null) {
+ m_elements = new Element[] { elem };
+ } else {
+ Element[] newElementsList = new Element[m_elements.length + 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, m_elements.length);
+ newElementsList[m_elements.length] = elem;
+ m_elements = newElementsList;
+ }
+ }
+
+ /**
+ * Removes an element from the {@link ManifestMetadataParser#m_elements} list.
+ * @return an element to remove
+ */
+ private Element removeLastElement() {
+ int idx = -1;
+ idx = m_elements.length - 1;
+ Element last = m_elements[idx];
+ if (idx >= 0) {
+ if ((m_elements.length - 1) == 0) {
+ // It is the last element of the list;
+ m_elements = new Element[0];
+ } else {
+ // Remove the last element of the list :
+ Element[] newElementsList = new Element[m_elements.length - 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, idx);
+ m_elements = newElementsList;
+ }
+ }
+ return last;
+ }
+
+ /**
+ * Looks for the <code>iPOJO-Components</code> header
+ * in the given dictionary. Then, initializes the
+ * {@link ManifestMetadataParser#m_elements} list (adds the
+ * <code>iPOJO</code> root element) and parses the contained
+ * component type declarations and instance configurations.
+ * @param dict the given headers of the manifest file
+ * @throws ParseException if any error occurs
+ */
+ public void parse(Dictionary dict) throws ParseException {
+ String componentClassesStr = (String) dict.get("iPOJO-Components");
+ // Add the ipojo element inside the element list
+ addElement(new Element("iPOJO", ""));
+ parseElements(componentClassesStr.trim());
+ }
+
+ /**
+ * Parses the given header, initialized the
+ * {@link ManifestMetadataParser#m_elements} list
+ * (adds the <code>iPOJO</code> element) and parses
+ * contained component type declarations and instance configurations.
+ * @param header the given header of the manifest file
+ * @throws ParseException if any error occurs
+ */
+ public void parseHeader(String header) throws ParseException {
+ // Add the ipojo element inside the element list
+ addElement(new Element("iPOJO", ""));
+ parseElements(header.trim());
+ }
+
+ /**
+ * Parses the metadata from the string given in argument.
+ * This methods creates a new {@link ManifestMetadataParser} object
+ * and calls the {@link ManifestMetadataParser#parseElements(String)}
+ * method. The parsing must result as a tree (only one root element).
+ * @param metadata the metadata to parse
+ * @return Element the root element resulting of the parsing
+ * @throws ParseException if any error occurs
+ */
+ public static Element parse(String metadata) throws ParseException {
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.parseElements(metadata);
+ if (parser.m_elements.length != 1) {
+ throw new ParseException("Error in parsing, root element not found : " + metadata);
+ }
+ return parser.m_elements[0];
+ }
+
+ /**
+ * Parses the metadata from the given header string.
+ * This method creates a new {@link ManifestMetadataParser} object and then
+ * creates the <code>iPOJO</code> root element, parses content elements
+ * (component types and instances declarations), and returns the resulting
+ * {@link Element} / {@link Attribute} structure. The parsed string
+ * must be a tree (only one root element).
+ * @param header the header to parse
+ * @return Element the root element resulting of the parsing
+ * @throws ParseException if any error occurs
+ */
+ public static Element parseHeaderMetadata(String header) throws ParseException {
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.addElement(new Element("iPOJO", ""));
+ parser.parseElements(header);
+ if (parser.m_elements.length != 1) {
+ throw new ParseException("Error in parsing, root element not found : " + header);
+ }
+ return parser.m_elements[0];
+ }
+
+ /**
+ * Parses the given string.
+ * This methods populates the {@link ManifestMetadataParser#m_elements}
+ * list.
+ * @param elems the string to parse
+ */
+ private void parseElements(String elems) {
+ char[] string = elems.toCharArray();
+
+ for (int i = 0; i < string.length; i++) {
+ char current = string[i];
+ switch (current) { //NOPMD
+ // Beginning of an attribute.
+ case '$':
+ StringBuffer attName = new StringBuffer();
+ StringBuffer attValue = new StringBuffer();
+ StringBuffer attNs = null;
+ i++;
+ current = string[i]; // Increment and get the new current char.
+ while (current != '=') {
+ if (current == ':') {
+ attNs = attName;
+ attName = new StringBuffer();
+ } else {
+ attName.append(current);
+ }
+ i++;
+ current = string[i];
+ }
+ i = i + 2; // skip ="
+ current = string[i];
+ while (current != '"') {
+ attValue.append(current);
+ i++;
+ current = string[i]; // Increment and get the new current char.
+ }
+ i++; // skip "
+ current = string[i];
+
+ Attribute att = null;
+ if (attNs == null) {
+ att = new Attribute(attName.toString(), attValue.toString());
+ } else {
+ att = new Attribute(attName.toString(), attNs.toString(), attValue.toString());
+ }
+ m_elements[m_elements.length - 1].addAttribute(att);
+ break;
+
+ // End of an element
+ case '}':
+ Element lastElement = removeLastElement();
+ if (m_elements.length == 0) {
+ addElement(lastElement);
+ } else {
+ Element newQueue = m_elements[m_elements.length - 1];
+ newQueue.addElement(lastElement);
+ }
+ break;
+
+ // Space
+ case ' ':
+ break; // do nothing;
+
+ // Default case
+ default:
+ StringBuffer qname = new StringBuffer();
+ current = string[i];
+ while (current != ' ') {
+ qname.append(current);
+ i++;
+ current = string[i]; // Increment and get the new current char.
+ }
+ // Skip spaces
+ while (string[i] == ' ') {
+ i = i + 1;
+ }
+ i = i + 1; // skip {
+
+ Element elem = null;
+ // Parse the qname
+ String n = qname.toString();
+ if (n.indexOf(':') == -1) {
+ // No namespace
+ elem = new Element(n, null);
+ } else {
+ // The namespace ends on the first ':'
+ int last = n.lastIndexOf(':');
+ String ns = n.substring(0, last);
+ String name = n.substring(last + 1);
+ elem = new Element(name.toString(), ns.toString());
+ }
+
+ addElement(elem);
+
+ break;
+ }
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java
new file mode 100644
index 0000000..71603bf
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/MethodMetadata.java
@@ -0,0 +1,246 @@
+/*
+ * 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.parser;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+
+/**
+ * A Method Metadata represents a method from the implementation class.
+ * This class allows getting information about a method : name, arguments, return type...
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadata {
+
+ /**
+ * Empty Constructor Method Id.
+ */
+ public static final String EMPTY_CONSTRUCTOR_ID = "$init";
+
+ /**
+ * Bundle Context Constructor Method Id.
+ */
+ public static final String BC_CONSTRUCTOR_ID = "$init$org_osgi_framework_BundleContext";
+
+ /**
+ * Constructor Prefix.
+ */
+ public static final String CONSTRUCTOR_PREFIX = "$init";
+
+
+ /**
+ * The name of the method.
+ */
+ private final String m_name;
+
+ /**
+ * The argument type array.
+ */
+ private final String[] m_arguments;
+
+ /**
+ * The returned type.
+ */
+ private final String m_return;
+
+ /**
+ * The argument names if there were contained in the manifest.
+ * @since 1.11.0
+ */
+ private final String[] m_names;
+
+ /**
+ * Creates a Method Metadata.
+ * @param metadata the method manipulation element.
+ */
+ public MethodMetadata(Element metadata) {
+ m_name = metadata.getAttribute("name");
+ String arg = metadata.getAttribute("arguments");
+ String names = metadata.getAttribute("names");
+ String result = metadata.getAttribute("return");
+ if (arg != null) {
+ m_arguments = ParseUtils.parseArrays(arg);
+ } else {
+ m_arguments = new String[0];
+ }
+ if (names != null) {
+ m_names = ParseUtils.parseArrays(names);
+ } else {
+ m_names = new String[0];
+ }
+
+ if (result != null) {
+ m_return = result;
+ } else {
+ m_return = "void";
+ }
+ }
+
+ public String getMethodName() {
+ return m_name;
+ }
+
+ public String[] getMethodArguments() {
+ return m_arguments;
+ }
+
+ public String[] getMethodArgumentNames() {
+ return m_names;
+ }
+
+ /**
+ * Gets the method arguments.
+ * The keys are the argument names, while the values are the argument type.
+ * @return the map of argument
+ * @since 1.10.2
+ */
+ public Map<String, String> getArguments() {
+ LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
+ for (int i = 0; i < m_names.length; i++) {
+ map.put(m_names[i], m_arguments[i]);
+ }
+ return map;
+ }
+
+ public String getMethodReturn() {
+ return m_return;
+ }
+
+ /**
+ * Gets the method unique identifier. For internal usage only.
+ * A method identifier is a unique string that can be a java field
+ * that identify the method.
+ * @return the method identifier.
+ */
+ public String getMethodIdentifier() {
+ StringBuffer identifier = new StringBuffer(m_name);
+ for (int i = 0; i < m_arguments.length; i++) {
+ String arg = m_arguments[i];
+ if (arg.endsWith("[]")) {
+ // We have to replace all []
+ String acc = "";
+ while (arg.endsWith("[]")) {
+ arg = arg.substring(0, arg.length() - 2);
+ acc += "__";
+ }
+ identifier.append("$" + arg.replace('.', '_') + acc);
+ } else {
+ identifier.append("$" + arg.replace('.', '_'));
+ }
+ }
+ return identifier.toString();
+ }
+
+ /**
+ * Computes the method id for the given Method object.
+ * @param method the Method object.
+ * @return the method id.
+ */
+ public static String computeMethodId(Method method) {
+ StringBuffer identifier = new StringBuffer(method.getName());
+ Class[] args = method.getParameterTypes();
+ for (int i = 0; i < args.length; i++) {
+ identifier.append('$'); // Argument separator.
+ if (args[i].isArray()) {
+ String acc = "__";
+ if (args[i].getComponentType().isPrimitive()) {
+ // Primitive array
+ identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i].getComponentType()));
+ } else if (args[i].getComponentType().isArray()) {
+ // Multi-directional array.
+ Class current = args[i].getComponentType();
+ while (current.isArray()) {
+ acc += "__";
+ current = current.getComponentType();
+ }
+ if (current.isPrimitive()) {
+ acc = FieldMetadata.getPrimitiveTypeByClass(current) + acc;
+ } else {
+ acc = current.getName().replace('.', '_') + acc;
+ }
+ } else {
+ // Object array
+ identifier.append(args[i].getComponentType().getName().replace('.', '_')); // Replace '.' by '_'
+ }
+ identifier.append(acc); // Add __ (array)
+ } else {
+ if (args[i].isPrimitive()) {
+ // Primitive type
+ identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i]));
+ } else {
+ // Object type
+ identifier.append(args[i].getName().replace('.', '_')); // Replace '.' by '_'
+ }
+ }
+ }
+ return identifier.toString();
+ }
+
+ /**
+ * Computes the method id for the given Constructor object.
+ * @param method the Method object.
+ * @return the method id.
+ */
+ public static String computeMethodId(Constructor method) {
+ StringBuffer identifier = new StringBuffer("$init");
+ Class[] args = method.getParameterTypes();
+ for (int i = 0; i < args.length; i++) {
+ // If the first argument is the InstanceManager skip it
+ if (i == 0 && InstanceManager.class.equals(args[i])) {
+ // Skip it.
+ continue;
+ }
+
+ identifier.append('$'); // Argument separator.
+ if (args[i].isArray()) {
+ String acc = "__";
+ if (args[i].getComponentType().isPrimitive()) {
+ // Primitive array
+ identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i].getComponentType()));
+ } else if (args[i].getComponentType().isArray()) {
+ // Multi-directional array.
+ Class current = args[i].getComponentType();
+ while (current.isArray()) {
+ acc += "__";
+ current = current.getComponentType();
+ }
+ } else {
+ // Object array
+ identifier.append(args[i].getComponentType().getName().replace('.', '_')); // Replace '.' by '_'
+ }
+ identifier.append(acc); // Add __ (array)
+ } else {
+ if (args[i].isPrimitive()) {
+ // Primitive type
+ identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i]));
+ } else {
+ // Object type
+ identifier.append(args[i].getName().replace('.', '_')); // Replace '.' by '_'
+ }
+ }
+ }
+ return identifier.toString();
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseException.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseException.java
new file mode 100644
index 0000000..1a1db2d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.parser;
+
+/**
+ * Exception thrown by parsers.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParseException extends Exception {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Parsing error.
+ * @param msg : the error emssage.
+ */
+ public ParseException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java
new file mode 100644
index 0000000..1ee2c41
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java
@@ -0,0 +1,85 @@
+/*
+ * 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.parser;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Parser Utility Methods.
+ * This class contains helper method to parse iPOJO metadata.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class ParseUtils {
+
+ /**
+ * Parses the iPOJO string form of an array as {a, b, c}
+ * or [a, b, c].
+ * @param str the string form
+ * @return the resulting string array
+ */
+ public static String[] parseArrays(String str) {
+ if (str.length() == 0) {
+ return new String[0];
+ }
+
+ // Remove { and } or [ and ]
+ if ((str.charAt(0) == '{' && str.charAt(str.length() - 1) == '}')
+ || (str.charAt(0) == '[' && str.charAt(str.length() - 1) == ']')) {
+ String internal = (str.substring(1, str.length() - 1)).trim();
+ // Check empty array
+ if (internal.length() == 0) {
+ return new String[0];
+ }
+ return split(internal, ",");
+ } else {
+ return new String[] { str };
+ }
+ }
+
+ /**
+ * Parses the string form of an array as {a, b, c}
+ * or [a, b, c] as a list.
+ * @param str the string form
+ * @return the resulting list
+ */
+ public static List<String> parseArraysAsList(String str) {
+ return Arrays.asList(parseArrays(str));
+ }
+
+ /**
+ * Split method.
+ * This method is equivalent of the String.split in java 1.4
+ * The result array contains 'trimmed' String
+ * @param toSplit the String to split
+ * @param separator the separator
+ * @return the split array
+ */
+ public static String[] split(String toSplit, String separator) {
+ StringTokenizer tokenizer = new StringTokenizer(toSplit, separator);
+ String[] result = new String[tokenizer.countTokens()];
+ int index = 0;
+ while (tokenizer.hasMoreElements()) {
+ result[index] = tokenizer.nextToken().trim();
+ index++;
+ }
+ return result;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/PojoMetadata.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/PojoMetadata.java
new file mode 100644
index 0000000..973ba49
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/parser/PojoMetadata.java
@@ -0,0 +1,306 @@
+/*
+ * 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.parser;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.*;
+
+/**
+ * Manipulation Metadata allows getting information about the implementation class
+ * without using reflection such as implemented interfaces, super class,
+ * methods and fields.
+ * This method allows getting object to register {@link org.apache.felix.ipojo.FieldInterceptor} and
+ * {@link org.apache.felix.ipojo.MethodInterceptor}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PojoMetadata {
+
+ /**
+ * The list of implemented interfaces.
+ */
+ private String[] m_interfaces = new String[0];
+
+ /**
+ * The list of fields.
+ */
+ private FieldMetadata[] m_fields = new FieldMetadata[0];
+
+ /**
+ * The list of methods.
+ */
+ private List<MethodMetadata> m_methods = new ArrayList<MethodMetadata>();
+
+ /**
+ * The Super class (if <code>null</code> for {@link Object}).
+ */
+ private String m_super;
+
+ /**
+ * The manipulated class name.
+ */
+ private String m_className;
+
+ /**
+ * The inner classes and their methods.
+ */
+ private Map<String, List<MethodMetadata>> m_innerClasses = new HashMap<String, List<MethodMetadata>>();
+
+
+ /**
+ * Creates Pojo metadata.
+ * Manipulation Metadata object are created from component type metadata by
+ * parsing manipulation metadata.
+ * @param metadata the component type metadata
+ * @throws ConfigurationException if the manipulation metadata cannot be found
+ */
+ public PojoMetadata(Element metadata) throws ConfigurationException {
+ Element[] elems = metadata.getElements("manipulation", "");
+ if (elems == null) {
+ throw new ConfigurationException("The component " + metadata.getAttribute("classname") + " has no manipulation metadata");
+ }
+ Element manip = elems[0];
+ m_className = manip.getAttribute("classname");
+ m_super = manip.getAttribute("super");
+
+ Element[] fields = manip.getElements("field");
+ if (fields != null) {
+ for (Element field : fields) {
+ addField(new FieldMetadata(field));
+ }
+ }
+
+ Element[] methods = manip.getElements("method");
+ if (methods != null) {
+ for (Element method : methods) {
+ m_methods.add(new MethodMetadata(method));
+ }
+ }
+
+ Element[] itfs = manip.getElements("interface");
+ if (itfs != null) {
+ for (Element itf : itfs) {
+ addInterface(itf.getAttribute("name"));
+ }
+ }
+
+ Element[] inners = manip.getElements("inner");
+ if (inners != null) {
+ for (Element inner : inners) {
+ String name = inner.getAttribute("name");
+ List<MethodMetadata> list = m_innerClasses.get(name);
+ if (list == null) {
+ list = new ArrayList<MethodMetadata>();
+ m_innerClasses.put(name, list);
+ }
+ methods = inner.getElements("method");
+ if (methods != null) {
+ for (Element m : methods) {
+ list.add(new MethodMetadata(m));
+ }
+ }
+ }
+ }
+ }
+
+ public MethodMetadata[] getMethods() { return m_methods.toArray(new MethodMetadata[m_methods.size()]); }
+
+ public FieldMetadata[] getFields() { return m_fields; }
+
+ public String[] getInterfaces() { return m_interfaces; }
+
+ public String getClassName() { return m_className; }
+
+ /**
+ * Gets the inner classes from the manipulated class
+ * @return the list of the inner class names.
+ */
+ public String[] getInnerClasses() {
+ Set<String> classes = m_innerClasses.keySet();
+ return classes.toArray(new String[classes.size()]);
+ }
+
+ /**
+ * Gets the methods from the given inner class.
+ * @param inner the inner class name
+ * @return the list of method, empty if none.
+ */
+ public MethodMetadata[] getMethodsFromInnerClass(String inner) {
+ List<MethodMetadata> methods = m_innerClasses.get(inner);
+ if (inner != null) {
+ return methods.toArray(new MethodMetadata[methods.size()]);
+ } else {
+ return new MethodMetadata[0];
+ }
+ }
+
+ /**
+ * Gets the field metadata for the given name.
+ * @param name : the name of the field
+ * @return the corresponding field metadata or <code>null</code> if not found
+ */
+ public FieldMetadata getField(String name) {
+ for (int i = 0; i < m_fields.length; i++) {
+ if (m_fields[i].getFieldName().equalsIgnoreCase(name)) { return m_fields[i]; }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the field metadata for the given name and type.
+ * @param name : the name of the field
+ * @param type : the type of the field
+ * @return the corresponding field metadata or <code>null</code> if not found
+ */
+ public FieldMetadata getField(String name, String type) {
+ for (int i = 0; i < m_fields.length; i++) {
+ if (m_fields[i].getFieldName().equalsIgnoreCase(name) && m_fields[i].getFieldType().equalsIgnoreCase(type)) { return m_fields[i]; }
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the given interface name is implemented.
+ * This methods checks on interface directly implemented
+ * by the implementation class.
+ * @param itf the interface to check.
+ * @return <code>true</code> if the implementation class implements
+ * the given interface.
+ */
+ public boolean isInterfaceImplemented(String itf) {
+ for (int i = 0; i < m_interfaces.length; i++) {
+ if (m_interfaces[i].equals(itf)) { return true; }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the MethodMetadata corresponding to the method
+ * (contained in the implementation class) with
+ * the given name.
+ * If several methods match, the first one is returned.
+ * @param name the name of the method to find.
+ * @return the method metadata object or <code>null</code> if not found
+ */
+ public MethodMetadata getMethod(String name) {
+ for (MethodMetadata metadata : m_methods) {
+ if (metadata.getMethodName().equalsIgnoreCase(name)) { return metadata; }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the MethodMetadata list corresponding to the method
+ * (contained in the implementation class) to given name.
+ * All methods contained in the implementation class matching
+ * with the name are in the returned list.
+ * @param name the name of the method to look for.
+ * @return the Method Metadata array or an empty array if not found
+ */
+ public MethodMetadata[] getMethods(String name) {
+ List<MethodMetadata> list = new ArrayList<MethodMetadata>();
+ for (MethodMetadata metadata : m_methods) {
+ if (metadata.getMethodName().equalsIgnoreCase(name)) {
+ list.add(metadata);
+ }
+ }
+ return list.toArray(new MethodMetadata[list.size()]);
+ }
+
+ /**
+ * Gets the MethodMetadata list corresponding to the constructors
+ * (contained in the implementation class).
+ * @return the Method Metadata array or an empty array if not found
+ */
+ public MethodMetadata[] getConstructors() {
+ return getMethods("$init");
+ }
+
+ /**
+ * Gets the MethodMetadata corresponding to the method
+ * (contained in the implementation class) to given name
+ * and argument types.
+ * @param name the name of the method to look for.
+ * @param types the array of the argument types of the method
+ * @return the Method Metadata or <code>null</code> if not found
+ */
+ public MethodMetadata getMethod(String name, String[] types) {
+ for (MethodMetadata metadata : m_methods) {
+ if (metadata.getMethodName().equalsIgnoreCase(name) && metadata.getMethodArguments().length == types.length) {
+ int argIndex = 0;
+ for (; argIndex < types.length; argIndex++) {
+ if (! types[argIndex].equals(metadata.getMethodArguments()[argIndex])) {
+ break;
+ }
+ }
+ if (argIndex == types.length) { return metadata; } // No mismatch detected.
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the constructor corresponding to the given argument types.
+ * @param types the argument types
+ * @return the matching constructor or <code>null</code> if not found.
+ */
+ public MethodMetadata getConstructor(String[] types) {
+ return getMethod("$init", types); // Constructors are named $init in the manipulation metadata
+ }
+
+ /**
+ * Adds a field to the list.
+ * This method is used during the creation of the {@link PojoMetadata}
+ * object.
+ * @param field the Field Metadata to add.
+ */
+ private void addField(FieldMetadata field) {
+ if (m_fields.length > 0) {
+ FieldMetadata[] newInstances = new FieldMetadata[m_fields.length + 1];
+ System.arraycopy(m_fields, 0, newInstances, 0, m_fields.length);
+ newInstances[m_fields.length] = field;
+ m_fields = newInstances;
+ } else {
+ m_fields = new FieldMetadata[] { field };
+ }
+ }
+
+ /**
+ * Adds the interface to the list.
+ * This method is used during the creation of the {@link PojoMetadata}
+ * object.
+ * @param itf the interface name to add.
+ */
+ private void addInterface(String itf) {
+ if (m_interfaces.length > 0) {
+ String[] newInstances = new String[m_interfaces.length + 1];
+ System.arraycopy(m_interfaces, 0, newInstances, 0, m_interfaces.length);
+ newInstances[m_interfaces.length] = itf;
+ m_interfaces = newInstances;
+ } else {
+ m_interfaces = new String[] { itf };
+ }
+ }
+
+ public String getSuperClass() {
+ return m_super;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Callback.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
new file mode 100644
index 0000000..826f663
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+
+/**
+ * A callback allows invoking a method on a POJO.
+ * This class supports both public, protected and private methods of the
+ * implementation class. This class also supports public method from super class.
+ * The {@link Method} object is computed once and this computation is delayed
+ * to the first invocation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Callback {
+
+ /**
+ * The method object.
+ * Computed at the first call.
+ */
+ protected Method m_methodObj;
+
+ /**
+ * The name of the method to call.
+ */
+ private String m_method;
+
+ /**
+ * Is the method a static method ?
+ * This implies calling the method on <code>null</code>
+ */
+ private boolean m_isStatic;
+
+ /**
+ * The reference on the instance manager.
+ * Used to get POJO objects.
+ */
+ private InstanceManager m_manager;
+
+ /**
+ * The argument classes.
+ * This array contains the list of argument class names.
+ */
+ private String[] m_args;
+
+ /**
+ * Creates a Callback.
+ * If the argument array is not null the reflection type are computed.
+ * @see Callback#computeArguments(String[])
+ * @param method the name of the method to call
+ * @param args the argument type name, or <code>null</code> if no arguments
+ * @param isStatic is the method a static method
+ * @param manager the instance manager of the component containing the method
+ */
+ public Callback(String method, String[] args, boolean isStatic, InstanceManager manager) {
+ m_method = method;
+ m_isStatic = isStatic;
+ m_manager = manager;
+ if (args != null) {
+ computeArguments(args);
+ } else {
+ m_args = new String[0];
+ }
+ }
+
+ /**
+ * Creates a Callback.
+ * @param method the the name of the method to call
+ * @param args the argument classes
+ * @param isStatic the is the method a static method
+ * @param manager the the instance manager of the component containing the method
+ */
+ public Callback(String method, Class[] args, boolean isStatic, InstanceManager manager) {
+ m_method = method;
+ m_isStatic = isStatic;
+ m_manager = manager;
+ m_args = new String[args.length];
+ for (int i = 0; i < args.length; i++) {
+ m_args[i] = args[i].getName();
+ }
+ }
+
+ /**
+ * Creates a Callback.
+ * @param method the {@link MethodMetadata} obtained from manipulation
+ * metadata ({@link org.apache.felix.ipojo.parser.PojoMetadata}).
+ * @param manager the instance manager.
+ */
+ public Callback(MethodMetadata method, InstanceManager manager) {
+ m_isStatic = false;
+ m_method = method.getMethodName();
+ m_manager = manager;
+ computeArguments(method.getMethodArguments());
+ }
+
+ /**
+ * Computes arguments of the method.
+ * This method computes "reflection type" from given argument.
+ * @see FieldMetadata#getReflectionType(String)
+ * @param args the arguments of the method.
+ */
+ private void computeArguments(String[] args) {
+ m_args = new String[args.length];
+ for (int i = 0; i < args.length; i++) {
+ m_args[i] = FieldMetadata.getReflectionType(args[i]);
+ }
+ }
+
+ /**
+ * Searches the {@link Method} in the given method arrays.
+ * @param methods the method array in which the method should be found
+ * @return the method object or <code>null</code> if not found
+ */
+ private Method searchMethodInMethodArray(Method[] methods) {
+ for (int i = 0; i < methods.length; i++) {
+ // First check the method name
+ if (methods[i].getName().equals(m_method)) {
+ // Check arguments
+ Class[] clazzes = methods[i].getParameterTypes();
+ if (clazzes.length == m_args.length) { // Test size to avoid useless loop
+ int argIndex = 0;
+ for (; argIndex < m_args.length; argIndex++) {
+ if (!m_args[argIndex].equals(clazzes[argIndex].getName())) {
+ break;
+ }
+ }
+ if (argIndex == m_args.length) { // No mismatch detected.
+ return methods[i]; // It is the looked method.
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Searches the {@link Method} object in the POJO by analyzing implementation
+ * class methods. The name of the method and the argument type are checked.
+ * @throws NoSuchMethodException if the method cannot be found either in the
+ * implementation class or in parent classes.
+ */
+ protected void searchMethod() throws NoSuchMethodException {
+ Method[] methods = m_manager.getClazz().getDeclaredMethods();
+ m_methodObj = searchMethodInMethodArray(methods);
+
+ if (m_methodObj == null) { // look at parent classes
+ methods = m_manager.getClazz().getMethods();
+ m_methodObj = searchMethodInMethodArray(methods);
+ }
+
+ if (m_methodObj == null) {
+ throw new NoSuchMethodException(m_method);
+ } else {
+ if (! m_methodObj.isAccessible()) {
+ // If not accessible, try to set the accessibility.
+ m_methodObj.setAccessible(true);
+ }
+ }
+ }
+
+ /**
+ * Invokes the method without arguments.
+ * If several the instance contains several objects, the method is invoked
+ * on every objects.
+ * @return the result of the invocation, <code>null</code> for <code>void</code>
+ * method, the last result for multi-object instance
+ * @throws NoSuchMethodException if Method is not found in the class
+ * @throws InvocationTargetException if the method throws an exception
+ * @throws IllegalAccessException if the method can not be invoked
+ */
+ public Object call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ return call(new Object[0]);
+ }
+
+ /**
+ * Invokes the method without arguments.
+ * The method is invokes on the specified object.
+ * @param instance the instance on which call the callback
+ * @return the result of the invocation, <code>null</code> for
+ * <code>void</code> method
+ * @throws NoSuchMethodException if the method was not found
+ * @throws IllegalAccessException if the method cannot be called
+ * @throws InvocationTargetException if an error happens in the method
+ */
+ public Object call(Object instance) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ return call(instance, new Object[0]);
+ }
+
+ /**
+ * Invokes the method on every created objects with the specified
+ * arguments.
+ * @param arg the method arguments
+ * @return the result of the invocation, <code>null</code> for
+ * <code>void</code> method, the last result for instance containing
+ * several objects.
+ * @throws NoSuchMethodException if the callback method is not found
+ * @throws IllegalAccessException if the callback method cannot be called
+ * @throws InvocationTargetException if an error is thrown by the called method
+ */
+ public Object call(Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ if (m_methodObj == null) {
+ searchMethod();
+ }
+
+ if (m_isStatic) {
+ return m_methodObj.invoke(null, arg);
+ } else {
+ // Two cases :
+ // - 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);
+ } else {
+ Object newObject = null;
+ for (int i = 0; i < m_manager.getPojoObjects().length; i++) {
+ newObject = m_methodObj.invoke(m_manager.getPojoObjects()[i], arg);
+ }
+ return newObject;
+ }
+ }
+ }
+
+ /**
+ * Invokes the method on the given object with the specified
+ * arguments.
+ * @param instance the instance on which call the method
+ * @param arg the argument array
+ * @return the result of the invocation, <code>null</code> for
+ * <code>void</code> method
+ * @throws NoSuchMethodException if the callback method is not found
+ * @throws IllegalAccessException if the callback method cannot be called
+ * @throws InvocationTargetException if an error is thrown by the called method
+ */
+ public Object call(Object instance, Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ if (m_methodObj == null) {
+ searchMethod();
+ }
+
+ return m_methodObj.invoke(instance, arg);
+ }
+
+ /**
+ * Gets the method name.
+ * @return the method name
+ */
+ public String getMethod() {
+ return m_method;
+ }
+
+ /**
+ * Gets the method arguments.
+ * @return the arguments.
+ */
+ public String[] getArguments() {
+ return m_args;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ContextSourceManager.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ContextSourceManager.java
new file mode 100644
index 0000000..a680df8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ContextSourceManager.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.List;
+
+/**
+ * This class manages context-source management.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ContextSourceManager implements ContextListener {
+
+ /**
+ * The variable prefix
+ */
+ public static final String VARIABLE_START = "${";
+
+ /**
+ * The variable end
+ */
+ public static final char VARIABLE_END = '}';
+
+ /**
+ * List of characters forbidden in variable names
+ */
+ public static final List<Character> FORBIDDEN_CHARACTERS = Arrays.asList(
+ '(', ')', '&', '|', '!', '=', '*', ' ');
+
+ /**
+ * Managed dependency.
+ */
+ private DependencyModel m_dependency;
+ /**
+ * List of monitored context sources.
+ */
+ private List<ContextSource> m_sources = new ArrayList<ContextSource>(1);
+ /**
+ * Variables contained in the original filter.
+ */
+ private List<String> m_variables;
+ /**
+ * Original filter (containing variables).
+ */
+ private String m_filter;
+ /**
+ * Bundle context.
+ */
+ private BundleContext m_context;
+ /**
+ * The Context-Source service tracker.
+ */
+ private Tracker m_tracker;
+
+ /**
+ * Creates the context source manager.
+ *
+ * @param dependency the dependency model on which this manager is plugged.
+ */
+ public ContextSourceManager(DependencyModel dependency) throws InvalidSyntaxException {
+ m_filter = dependency.getFilter();
+ m_variables = extractVariablesFromFilter(m_filter);
+ m_dependency = dependency;
+ m_context = dependency.getComponentInstance().getContext();
+ }
+
+ /**
+ * This method substitutes ${var} substring by values stored in a map.
+ *
+ * @param str : string with variables
+ * @param values : dictionary containing the variable name and the value.
+ * @return resulted string
+ */
+ public static String substitute(String str, Dictionary values) {
+ int len = str.length();
+ StringBuilder builder = new StringBuilder(len);
+
+ int prev = 0;
+ int start = str.indexOf("${");
+ int end = str.indexOf('}', start);
+ while (start != -1 && end != -1) {
+ String key = str.substring(start + 2, end);
+ Object value = values.get(key);
+ if (value == null) {
+ builder.append(str.substring(prev, end + 1));
+ } else {
+ builder.append(str.substring(prev, start));
+ builder.append(value);
+ }
+ prev = end + 1;
+ if (prev >= str.length()) {
+ break;
+ }
+
+ start = str.indexOf("${", prev);
+ if (start != -1) {
+ end = str.indexOf('}', start);
+ }
+ }
+
+ builder.append(str.substring(prev));
+
+ return builder.toString();
+ }
+
+ /**
+ * Extracts the variables (${name}) from the given filter.
+ *
+ * @param filter : string form of the filter.
+ * @return the list of found properties.
+ * @throws InvalidSyntaxException thrown when the variables are not consistent.
+ */
+ public static List<String> extractVariablesFromFilter(String filter) throws InvalidSyntaxException {
+ List<String> variables = new ArrayList<String>();
+ int prev;
+ int start = filter.indexOf(VARIABLE_START);
+ int end = filter.indexOf(VARIABLE_END, start);
+ while (start != -1) {
+ // Unfinished variable
+ if (end == -1) {
+ throw new InvalidSyntaxException("The filter contains an unfinished variable", filter);
+ }
+
+ String key = filter.substring(start + VARIABLE_START.length(), end);
+
+ // Error detection :
+ // Empty variable.
+ if (key.length() == 0) {
+ throw new InvalidSyntaxException("The filter variable '${}' is not a valid " +
+ "variable", filter);
+ }
+ // Variable with spaces.
+ Character forbidden = containsForbiddenCharacter(key);
+ if (forbidden != null) {
+ throw new InvalidSyntaxException("The filter variable '${" + key + "}' contains a forbidden " +
+ "character : '" + forbidden + "'", filter);
+ }
+
+
+ variables.add(key);
+ prev = end + 1;
+ if (prev >= filter.length()) {
+ break;
+ }
+
+ start = filter.indexOf(VARIABLE_START, prev);
+ if (start != -1) {
+ end = filter.indexOf(VARIABLE_END, start);
+ }
+ }
+
+ return variables;
+ }
+
+ private static Character containsForbiddenCharacter(String key) {
+ for (Character character : FORBIDDEN_CHARACTERS) {
+ if (key.indexOf(character) != -1) {
+ return character;
+ }
+ }
+ // Safe key.
+ return null;
+ }
+
+ /**
+ * Start the context management.
+ */
+ public void start() {
+ if (m_tracker == null) {
+ m_tracker = new Tracker(m_context, ContextSource.class.getName(), new SourceTracker());
+ }
+ m_tracker.open();
+ computeFilter();
+ }
+
+ /**
+ * Stop the context management.
+ */
+ public void stop() {
+ if (m_tracker != null) {
+ m_tracker.close();
+ m_tracker = null;
+ }
+ // Reinitialize the filter.
+ setFilter(m_filter);
+ for (ContextSource source : m_sources) {
+ source.unregisterContextListener(this);
+ }
+ m_sources.clear();
+ }
+
+ /**
+ * Set the filter of the managed dependency.
+ *
+ * @param filter : the new filter to apply
+ */
+ private void setFilter(String filter) {
+ if (!filter.equals(m_dependency.getFilter())) {
+ // Reconfigure
+ try {
+ m_dependency.setFilter(m_context.createFilter(filter));
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException("A context filter is invalid : " + filter, e);
+ }
+ }
+ }
+
+ /**
+ * Compute the new filter.
+ */
+ private void computeFilter() {
+ String fil = m_filter; // Gets a copy.
+ synchronized (this) {
+ for (ContextSource m_source : m_sources) {
+ Dictionary props = m_source.getContext();
+ fil = substitute(fil, props); //NOPMD
+ }
+ }
+ if (!fil.equals(m_dependency.getFilter())) {
+ setFilter(fil);
+ }
+ }
+
+ /**
+ * A context source has modified a monitored property.
+ *
+ * @param source : source
+ * @param property : modified property
+ * @param value : new value.
+ * @see org.apache.felix.ipojo.ContextListener#update(org.apache.felix.ipojo.ContextSource, String, Object)
+ */
+ public synchronized void update(ContextSource source, String property, Object value) {
+ computeFilter();
+ }
+
+ /**
+ * A context source appears.
+ *
+ * @param source : new context source.
+ */
+ public void addContextSource(ContextSource source) {
+ m_sources.add(source);
+ computeFilter();
+ source.registerContextListener(this, m_variables.toArray(new String[m_variables.size()]));
+ }
+
+ /**
+ * A context source disappears.
+ *
+ * @param source : leaving context source.
+ */
+ public void removeContextSource(ContextSource source) {
+ source.unregisterContextListener(this);
+ m_sources.remove(source);
+ computeFilter();
+ }
+
+ private class SourceTracker implements TrackerCustomizer {
+ /**
+ * A new context-source was added.
+ * This method inject the context-source object in the source manager.
+ *
+ * @param reference : service reference.
+ * @see TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void addedService(ServiceReference reference) {
+ addContextSource((ContextSource) m_tracker.getService(reference));
+ }
+
+ /**
+ * A new context-source is adding in the tracker..
+ *
+ * @param reference : service reference
+ * @return true.
+ * @see TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+ */
+ public boolean addingService(ServiceReference reference) {
+ return true;
+ }
+
+ /**
+ * A used context-source is modified.
+ *
+ * @param reference : service reference.
+ * @param service : service object.
+ * @see TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, Object)
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Nothing to do.
+ }
+
+ /**
+ * A used context-source disappears.
+ * This method notify the Source Manager in order to manage this departure.
+ *
+ * @param reference : service reference.
+ * @param service : service object.
+ * @see TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, Object)
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ removeContextSource((ContextSource) service);
+ }
+
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyMetadataHelper.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyMetadataHelper.java
new file mode 100644
index 0000000..bc1b7cd
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyMetadataHelper.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+import java.util.Comparator;
+
+/**
+ * A set of methods to simplify the parsing of dependency attributes.
+ */
+public class DependencyMetadataHelper {
+
+
+ /**
+ * Helper method parsing the comparator attribute and returning the
+ * comparator object. If the 'comparator' attribute is not set, this method
+ * returns null. If the 'comparator' attribute is set to 'osgi', this method
+ * returns the normal OSGi comparator. In other case, it tries to create
+ * an instance of the declared comparator class.
+ *
+ * @param dep the Element describing the dependency
+ * @param context the bundle context (to load the comparator class)
+ * @return the comparator object, <code>null</code> if not set.
+ * @throws org.apache.felix.ipojo.ConfigurationException the comparator class cannot be load or the
+ * comparator cannot be instantiated correctly.
+ */
+ public static Comparator getComparator(Element dep, BundleContext context) throws ConfigurationException {
+ Comparator cmp = null;
+ String comp = dep.getAttribute("comparator");
+ if (comp != null) {
+ if (comp.equalsIgnoreCase("osgi")) {
+ cmp = new ServiceReferenceRankingComparator();
+ } else {
+ try {
+ Class cla = context.getBundle().loadClass(comp);
+ cmp = (Comparator) cla.newInstance();
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Cannot load a customized comparator", e);
+ } catch (IllegalAccessException e) {
+ throw new ConfigurationException("Cannot create a customized comparator", e);
+ } catch (InstantiationException e) {
+ throw new ConfigurationException("Cannot create a customized comparator", e);
+ }
+ }
+ }
+ return cmp;
+ }
+
+ /**
+ * Loads the given specification class.
+ *
+ * @param specification the specification class name to load
+ * @param context the bundle context
+ * @return the class object for the given specification
+ * @throws org.apache.felix.ipojo.ConfigurationException if the class cannot be loaded correctly.
+ */
+ public static Class loadSpecification(String specification, BundleContext context) throws ConfigurationException {
+ Class spec;
+ try {
+ spec = context.getBundle().loadClass(specification);
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("A required specification cannot be loaded : " + specification, e);
+ }
+ return spec;
+ }
+
+ /**
+ * Helper method parsing the binding policy.
+ * If the 'policy' attribute is not set in the dependency, the method returns
+ * the 'DYNAMIC BINDING POLICY'. Accepted policy values are : dynamic,
+ * dynamic-priority and static.
+ *
+ * @param dep the Element describing the dependency
+ * @return the policy attached to this dependency
+ * @throws org.apache.felix.ipojo.ConfigurationException if an unknown binding policy was described.
+ */
+ public static int getPolicy(Element dep) throws ConfigurationException {
+ String policy = dep.getAttribute("policy");
+ if (policy == null || policy.equalsIgnoreCase("dynamic")) {
+ return DependencyModel.DYNAMIC_BINDING_POLICY;
+ } else if (policy.equalsIgnoreCase("dynamic-priority")) {
+ return DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY;
+ } else if (policy.equalsIgnoreCase("static")) {
+ return DependencyModel.STATIC_BINDING_POLICY;
+ } else {
+ throw new ConfigurationException("Binding policy unknown : " + policy);
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
new file mode 100644
index 0000000..1040787
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
@@ -0,0 +1,1277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+import org.apache.felix.ipojo.dependency.impl.ServiceReferenceManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Abstract dependency model.
+ * This class is the parent class of every service dependency. It manages the most
+ * part of dependency management. This class creates an interface between the service
+ * tracker and the concrete dependency.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class DependencyModel {
+
+ /**
+ * Dependency state : BROKEN.
+ * A broken dependency cannot be fulfilled anymore. The dependency becomes
+ * broken when a used service disappears in the static binding policy.
+ */
+ public static final int BROKEN = -1;
+ /**
+ * Dependency state : UNRESOLVED.
+ * A dependency is unresolved if the dependency is not valid and no service
+ * providers are available.
+ */
+ public static final int UNRESOLVED = 0;
+ /**
+ * Dependency state : RESOLVED.
+ * A dependency is resolved if the dependency is optional or at least one
+ * provider is available.
+ */
+ public static final int RESOLVED = 1;
+ /**
+ * Binding policy : Dynamic.
+ * In this policy, services can appears and departs without special treatment.
+ */
+ public static final int DYNAMIC_BINDING_POLICY = 0;
+ /**
+ * Binding policy : Static.
+ * Once a service is used, if this service disappears the dependency becomes
+ * {@link DependencyModel#BROKEN}. The instance needs to be recreated.
+ */
+ public static final int STATIC_BINDING_POLICY = 1;
+ /**
+ * Binding policy : Dynamic-Priority.
+ * In this policy, services can appears and departs. However, once a service
+ * with a highest ranking (according to the used comparator) appears, this
+ * new service is re-injected.
+ */
+ public static final int DYNAMIC_PRIORITY_BINDING_POLICY = 2;
+ /**
+ * The service reference manager.
+ */
+ protected final ServiceReferenceManager m_serviceReferenceManager;
+ /**
+ * The manager handling context sources.
+ */
+ private final ContextSourceManager m_contextSourceManager;
+ /**
+ * Listener object on which invoking the {@link DependencyStateListener#validate(DependencyModel)}
+ * and {@link DependencyStateListener#invalidate(DependencyModel)} methods.
+ */
+ private final DependencyStateListener m_listener;
+ /**
+ * The instance requiring the service.
+ */
+ private final ComponentInstance m_instance;
+ /**
+ * Does the dependency bind several providers ?
+ */
+ private boolean m_aggregate;
+ /**
+ * Is the dependency optional ?
+ */
+ private boolean m_optional;
+ /**
+ * The required specification.
+ * Cannot change once set.
+ */
+ private Class m_specification;
+ /**
+ * Bundle context used by the dependency.
+ * (may be a {@link org.apache.felix.ipojo.ServiceContext}).
+ */
+ private BundleContext m_context;
+ /**
+ * The actual state of the dependency.
+ * {@link DependencyModel#UNRESOLVED} at the beginning.
+ */
+ private int m_state;
+ /**
+ * The Binding policy of the dependency.
+ */
+ private int m_policy = DYNAMIC_BINDING_POLICY;
+ /**
+ * The tracker used by this dependency to track providers.
+ */
+ private Tracker m_tracker;
+ /**
+ * Map {@link ServiceReference} -> Service Object.
+ * This map stores service object, and so is able to handle
+ * iPOJO custom policies.
+ */
+ private Map<ServiceReference, ServiceBindingHolder> m_serviceObjects = new HashMap<ServiceReference, ServiceBindingHolder>();
+ /**
+ * The current list of bound services.
+ */
+ private List<ServiceReference> m_boundServices = new ArrayList<ServiceReference>();
+ /**
+ * The lock ensuring state consistency of the dependency.
+ * This lock can be acquired from all collaborators.
+ */
+ private ReentrantReadWriteLock m_lock = new ReentrantReadWriteLock();
+
+ /**
+ * The listeners of the dependency model.
+ */
+ private final List<DependencyModelListener> m_listeners = new ArrayList<DependencyModelListener>();
+
+ /**
+ * Creates a DependencyModel.
+ * If the dependency has no comparator and follows the
+ * {@link DependencyModel#DYNAMIC_PRIORITY_BINDING_POLICY} policy
+ * the OSGi Service Reference Comparator is used.
+ *
+ * @param specification the required specification
+ * @param aggregate is the dependency aggregate ?
+ * @param optional is the dependency optional ?
+ * @param filter the LDAP filter
+ * @param comparator the comparator object to sort references
+ * @param policy the binding policy
+ * @param context the bundle context (or service context)
+ * @param listener the dependency lifecycle listener to notify from dependency
+ * @param ci instance managing the dependency
+ * state changes.
+ */
+ public DependencyModel(Class specification, boolean aggregate, boolean optional, Filter filter,
+ Comparator<ServiceReference> comparator, int policy,
+ BundleContext context, DependencyStateListener listener, ComponentInstance ci) {
+ m_specification = specification;
+ m_aggregate = aggregate;
+ m_optional = optional;
+
+ m_instance = ci;
+
+ m_policy = policy;
+ // If the dynamic priority policy is chosen, and we have no comparator, fix it to OSGi standard service reference comparator.
+ if (m_policy == DYNAMIC_PRIORITY_BINDING_POLICY && comparator == null) {
+ comparator = new ServiceReferenceRankingComparator();
+ }
+
+ if (context != null) {
+ m_context = context;
+ // If the context is null, it gonna be set later using the setBundleContext method.
+ }
+
+ m_serviceReferenceManager = new ServiceReferenceManager(this, filter, comparator);
+
+ if (filter != null) {
+ try {
+ m_contextSourceManager = new ContextSourceManager(this);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ } else {
+ m_contextSourceManager = null;
+ }
+ m_state = UNRESOLVED;
+ m_listener = listener;
+ }
+
+ /**
+ * Opens the tracking.
+ * This method computes the dependency state.
+ * <p/>
+ * As the dependency is starting, locking is not required here.
+ *
+ * @see DependencyModel#computeAndSetDependencyState()
+ */
+ public void start() {
+ m_state = UNRESOLVED;
+ m_tracker = new Tracker(m_context, m_specification.getName(), m_serviceReferenceManager);
+ m_serviceReferenceManager.open();
+ m_tracker.open();
+
+ if (m_contextSourceManager != null) {
+ m_contextSourceManager.start();
+ }
+
+ computeAndSetDependencyState();
+ }
+
+ /**
+ * Gets the bundle context used by the dependency.
+ * @return the bundle context
+ */
+ public BundleContext getBundleContext() {
+ // Immutable member, no lock required.
+ return m_context;
+ }
+
+ /**
+ * This callback is called by ranking interceptor to notify the dependency that the selected service set has
+ * changed and must be recomputed.
+ */
+ public void invalidateSelectedServices() {
+ m_serviceReferenceManager.invalidateSelectedServices();
+ }
+
+ public void invalidateMatchingServices() {
+ m_serviceReferenceManager.invalidateMatchingServices();
+ }
+
+ /**
+ * Closes the tracking.
+ * The dependency becomes {@link DependencyModel#UNRESOLVED}
+ * at the end of this method.
+ */
+ public void stop() {
+ // We're stopping, we must take the exclusive lock
+ try {
+ acquireWriteLockIfNotHeld();
+ if (m_tracker != null) {
+ m_tracker.close();
+ m_tracker = null;
+ }
+ m_boundServices.clear();
+ m_serviceReferenceManager.close();
+ ungetAllServices();
+ m_state = UNRESOLVED;
+ if (m_contextSourceManager != null) {
+ m_contextSourceManager.stop();
+ }
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ /**
+ * Ungets all 'get' service references.
+ * This also clears the service object map.
+ * The method is called while holding the exclusive lock.
+ */
+ private void ungetAllServices() {
+ for (Map.Entry<ServiceReference, ServiceBindingHolder> entry : m_serviceObjects.entrySet()) {
+ ServiceReference ref = entry.getKey();
+ ServiceBindingHolder sbh = entry.getValue();
+ if (m_tracker != null) {
+ m_tracker.ungetService(ref);
+ }
+ if (sbh.factory != null) {
+ sbh.factory.ungetService(m_instance, sbh.service);
+ }
+ m_serviceReferenceManager.unweavingServiceBinding(sbh);
+ }
+ m_serviceObjects.clear();
+ }
+
+ /**
+ * Is the reference set frozen (cannot change anymore)?
+ * This method must be override by concrete dependency to support
+ * the static binding policy. In fact, this method allows optimizing
+ * the static dependencies to become frozen only when needed.
+ * This method returns <code>false</code> by default.
+ * The method must always return <code>false</code> for non-static dependencies.
+ *
+ * @return <code>true</code> if the reference set is frozen.
+ */
+ public boolean isFrozen() {
+ return false;
+ }
+
+ /**
+ * Unfreezes the dependency.
+ * This method must be override by concrete dependency to support
+ * the static binding policy. This method is called after tracking restarting.
+ */
+ public void unfreeze() {
+ // nothing to do
+ }
+
+ /**
+ * Does the service reference match ? This method must be overridden by
+ * concrete dependencies if they need advanced testing on service reference
+ * (that cannot be expressed in the LDAP filter). By default this method
+ * returns <code>true</code>.
+ *
+ * @param ref the tested reference.
+ * @return <code>true</code> if the service reference matches.
+ */
+ public boolean match(ServiceReference ref) {
+ return true;
+ }
+
+ /**
+ * Computes the actual dependency state.
+ * This methods invokes the {@link DependencyStateListener}.
+ * If this method is called without the write lock, it takes it. Anyway, the lock will be released before called
+ * the
+ * callbacks.
+ */
+ private void computeAndSetDependencyState() {
+ try {
+ boolean mustCallValidate = false;
+ boolean mustCallInvalidate = false;
+
+ acquireWriteLockIfNotHeld();
+
+ // The dependency is broken, nothing else can be done
+ if (m_state == BROKEN) {
+ return;
+ }
+
+ if (m_optional || !m_serviceReferenceManager.isEmpty()) {
+ // The dependency is valid
+ if (m_state == UNRESOLVED) {
+ m_state = RESOLVED;
+ mustCallValidate = true;
+ }
+ } else {
+ // The dependency is invalid
+ if (m_state == RESOLVED) {
+ m_state = UNRESOLVED;
+ mustCallInvalidate = true;
+ }
+ }
+
+ // Invoke callback in a non-synchronized region
+ // First unlock the lock
+ releaseWriteLockIfHeld();
+ // Now we can call the callbacks
+ if (mustCallInvalidate) {
+ invalidate();
+ } else if (mustCallValidate) {
+ validate();
+ }
+ } finally {
+ // If we are still holding the exclusive lock, unlock it.
+ releaseWriteLockIfHeld();
+ }
+
+ }
+
+ /**
+ * Gets the first bound service reference.
+ *
+ * @return <code>null</code> if no more provider is available,
+ * else returns the first reference from the matching set.
+ */
+ public ServiceReference getServiceReference() {
+ // Read lock required
+ try {
+ acquireReadLockIfNotHeld();
+ if (m_boundServices.isEmpty()) {
+ return null;
+ } else {
+ return m_boundServices.get(0);
+ }
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets bound service references.
+ *
+ * @return the sorted (if a comparator is used) array of matching service
+ * references, <code>null</code> if no references are available.
+ */
+ public ServiceReference[] getServiceReferences() {
+ // Read lock required
+ try {
+ acquireReadLockIfNotHeld();
+ if (m_boundServices.isEmpty()) {
+ return null;
+ }
+ return m_boundServices.toArray(new ServiceReference[m_boundServices.size()]);
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets the list of currently used service references.
+ * If no service references, returns <code>null</code>
+ *
+ * @return the list of used reference (according to the service tracker).
+ */
+ public List<ServiceReference> getUsedServiceReferences() {
+ // Read lock required
+ try {
+ acquireReadLockIfNotHeld();
+ // The list must confront actual matching services with already get services from the tracker.
+
+ int size = m_boundServices.size();
+ List<ServiceReference> usedByTracker = null;
+ if (m_tracker != null) {
+ usedByTracker = m_tracker.getUsedServiceReferences();
+ }
+ if (size == 0 || usedByTracker == null) {
+ return null;
+ }
+
+ List<ServiceReference> list = new ArrayList<ServiceReference>(1);
+ for (ServiceReference ref : m_boundServices) {
+ if (usedByTracker.contains(ref)) {
+ list.add(ref); // Add the service in the list.
+ if (!isAggregate()) { // IF we are not multiple, return the list when the first element is found.
+ return list;
+ }
+ }
+ }
+
+ return list;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * @return the component instance on which this dependency is plugged.
+ */
+ public ComponentInstance getComponentInstance() {
+ // No lock required as m_instance is final
+ return m_instance;
+ }
+
+ /**
+ * Gets the number of actual matching references.
+ *
+ * @return the number of matching references
+ */
+ public int getSize() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_boundServices.size();
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Concrete dependency callback.
+ * This method is called when a new service needs to be
+ * re-injected in the underlying concrete dependency.
+ *
+ * @param ref the service reference to inject.
+ */
+ public abstract void onServiceArrival(ServiceReference ref);
+
+ /**
+ * Concrete dependency callback.
+ * This method is called when a used service (already injected) is leaving.
+ *
+ * @param ref the leaving service reference.
+ */
+ public abstract void onServiceDeparture(ServiceReference ref);
+
+ /**
+ * Concrete dependency callback.
+ * This method is called when a used service (already injected) is modified.
+ *
+ * @param ref the modified service reference.
+ */
+ public abstract void onServiceModification(ServiceReference ref);
+
+ /**
+ * Concrete dependency callback.
+ * This method is called when the dependency is reconfigured and when this
+ * reconfiguration implies changes on the matching service set ( and by the
+ * way on the injected service).
+ *
+ * @param departs the service leaving the matching set.
+ * @param arrivals the service arriving in the matching set.
+ */
+ public abstract void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals);
+
+ /**
+ * Calls the listener callback to notify the new state of the current
+ * dependency.
+ * No lock hold when calling this callback.
+ */
+ private void invalidate() {
+ m_listener.invalidate(this);
+ // Notify dependency invalidation to listeners
+ notifyListeners(DependencyEventType.INVALIDATE, null, null);
+ }
+
+ /**
+ * Calls the listener callback to notify the new state of the current
+ * dependency.
+ * No lock hold when calling this callback.
+ */
+ private void validate() {
+ m_listener.validate(this);
+ // Notify dependency validation to listeners
+ notifyListeners(DependencyEventType.VALIDATE, null, null);
+ }
+
+ /**
+ * Gets the actual state of the dependency.
+ * @return the state of the dependency.
+ */
+ public int getState() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_state;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets the tracked specification.
+ *
+ * @return the Class object tracked by the dependency.
+ */
+ public Class getSpecification() {
+ return m_specification;
+ }
+
+ /**
+ * Sets the required specification of this service dependency.
+ * This operation is not supported if the dependency tracking has already begun.
+ * So, we don't have to hold a lock.
+ *
+ * @param specification the required specification.
+ */
+ public void setSpecification(Class specification) {
+ if (m_tracker == null) {
+ m_specification = specification;
+ } else {
+ throw new UnsupportedOperationException("Dynamic specification change is not yet supported");
+ }
+ }
+
+ /**
+ * Acquires the write lock only and only if the write lock is not already held by the current thread.
+ * @return {@literal true} if the lock was acquired within the method, {@literal false} otherwise.
+ */
+ public boolean acquireWriteLockIfNotHeld() {
+ if (! m_lock.isWriteLockedByCurrentThread()) {
+ m_lock.writeLock().lock();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Releases the write lock only and only if the write lock is held by the current thread.
+ * @return {@literal true} if the lock has no more holders, {@literal false} otherwise.
+ */
+ public boolean releaseWriteLockIfHeld() {
+ if (m_lock.isWriteLockedByCurrentThread()) {
+ m_lock.writeLock().unlock();
+ }
+ return m_lock.getWriteHoldCount() == 0;
+ }
+
+ /**
+ * Acquires the read lock only and only if no read lock is already held by the current thread.
+ *
+ * As the introspection methods provided by this method are java 6+, we just take a read lock.
+ * @return {@literal true} if the lock was acquired within the method, {@literal false} otherwise.
+ */
+ public boolean acquireReadLockIfNotHeld() {
+ m_lock.readLock().lock();
+ return true;
+ }
+
+ /**
+ * Releases the read lock only and only if the read lock is held by the current thread.
+ * * As the introspection methods provided by this method are java 6+, we just unlock the read lock.
+ * @return {@literal true} if the lock has no more holders, {@literal false} otherwise.
+ */
+ public boolean releaseReadLockIfHeld() {
+ try {
+ m_lock.readLock().unlock();
+ } catch (IllegalMonitorStateException e) {
+ // Oupsy we were not holding the lock...
+ }
+ return true;
+ }
+
+ /**
+ * Returns the dependency filter (String form).
+ *
+ * @return the String form of the LDAP filter used by this dependency,
+ * <code>null</code> if not set.
+ */
+ public String getFilter() {
+ Filter filter;
+ try {
+ acquireReadLockIfNotHeld();
+ filter = m_serviceReferenceManager.getFilter();
+ } finally {
+ releaseReadLockIfHeld();
+ }
+
+ if (filter == null) {
+ return null;
+ } else {
+ return filter.toString();
+ }
+ }
+
+ /**
+ * Sets the filter of the dependency. This method recomputes the
+ * matching set and call the onDependencyReconfiguration callback.
+ *
+ * @param filter the new LDAP filter.
+ */
+ public void setFilter(Filter filter) {
+ try {
+ acquireWriteLockIfNotHeld();
+ ServiceReferenceManager.ChangeSet changeSet = m_serviceReferenceManager.setFilter(filter, m_tracker);
+ // We call this method when holding the lock, but the method may decide to release the lock to invoke
+ // callbacks, so we must defensively unlock the lock in the finally block.
+ applyReconfiguration(changeSet);
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ /**
+ * Applies the given reconfiguration.
+ * This method check if the current thread is holding the write lock, if not, acquire it.
+ * The lock will be released before calling callbacks. As a consequence, the caller has to check if the lock is
+ * still hold when this method returns.
+ * @param changeSet the reconfiguration changes
+ */
+ public void applyReconfiguration(ServiceReferenceManager.ChangeSet changeSet) {
+ List<ServiceReference> arr = new ArrayList<ServiceReference>();
+ List<ServiceReference> dep = new ArrayList<ServiceReference>();
+
+ try {
+ acquireWriteLockIfNotHeld();
+ if (m_tracker == null) {
+ // Nothing else to do.
+ return;
+ } else {
+ // Update bindings
+ m_boundServices.clear();
+ if (m_aggregate) {
+ m_boundServices = new ArrayList<ServiceReference>(changeSet.selected);
+ arr = changeSet.arrivals;
+ dep = changeSet.departures;
+ } else {
+ ServiceReference used = null;
+ if (!m_boundServices.isEmpty()) {
+ used = m_boundServices.get(0);
+ }
+
+ if (!changeSet.selected.isEmpty()) {
+ final ServiceReference best = changeSet.newFirstReference;
+ // We didn't a provider
+ if (used == null) {
+ // We are not bound with anyone yet, so take the first of the selected set
+ m_boundServices.add(best);
+ arr.add(best);
+ } else {
+ // A provider was already bound, did we changed ?
+ if (changeSet.selected.contains(used)) {
+ // We are still valid - but in dynamic priority, we may have to change
+ if (getBindingPolicy() == DYNAMIC_PRIORITY_BINDING_POLICY && used != best) {
+ m_boundServices.add(best);
+ dep.add(used);
+ arr.add(best);
+ } else {
+ // We restore the old binding.
+ m_boundServices.add(used);
+ }
+ } else {
+ // The used service has left.
+ m_boundServices.add(best);
+ dep.add(used);
+ arr.add(best);
+ }
+ }
+ } else {
+ // We don't have any service anymore
+ if (used != null) {
+ arr.add(used);
+ }
+ }
+ }
+ }
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+
+ // This method releases the exclusive lock.
+ computeAndSetDependencyState();
+
+ // As the previous method has released the lock, we can call the callback safely.
+ onDependencyReconfiguration(
+ dep.toArray(new ServiceReference[dep.size()]),
+ arr.toArray(new ServiceReference[arr.size()]));
+
+ // Notify dependency reconfiguration to listeners
+ notifyListeners(DependencyEventType.RECONFIGURED, null, null);
+ }
+
+ public boolean isAggregate() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_aggregate;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Sets the aggregate attribute of the current dependency.
+ * If the tracking is opened, it will call arrival and departure callbacks.
+ *
+ * @param isAggregate the new aggregate attribute value.
+ */
+ public void setAggregate(boolean isAggregate) {
+ // Acquire the write lock here.
+ acquireWriteLockIfNotHeld();
+ List<ServiceReference> arrivals = new ArrayList<ServiceReference>();
+ List<ServiceReference> departures = new ArrayList<ServiceReference>();
+ try {
+ if (m_tracker == null) { // Not started ...
+ m_aggregate = isAggregate;
+ } else {
+ // We become aggregate.
+ if (!m_aggregate && isAggregate) {
+ m_aggregate = true;
+ // Call the callback on all non already injected service.
+ if (m_state == RESOLVED) {
+
+ for (ServiceReference ref : m_serviceReferenceManager.getSelectedServices()) {
+ if (!m_boundServices.contains(ref)) {
+ m_boundServices.add(ref);
+ arrivals.add(ref);
+ }
+ }
+ }
+ } else if (m_aggregate && !isAggregate) {
+ m_aggregate = false;
+ // We become non-aggregate.
+ if (m_state == RESOLVED) {
+ List<ServiceReference> list = new ArrayList<ServiceReference>(m_boundServices);
+ for (int i = 1; i < list.size(); i++) { // The loop begin at 1, as the 0 stays injected.
+ m_boundServices.remove(list.get(i));
+ departures.add(list.get(i));
+ }
+ }
+ }
+ // Else, do nothing.
+ }
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+
+ // TODO shouldn't we call onDependencyReconfiguration here????
+
+ // Now call callbacks, the lock is not held anymore
+ // Only one of the list is not empty..
+ try {
+ acquireReadLockIfNotHeld();
+ for (ServiceReference ref : arrivals) {
+ onServiceArrival(ref);
+ // Notify service binding to listeners
+ notifyListeners(DependencyEventType.BINDING, ref, m_serviceObjects.get(ref).service);
+ }
+ for (ServiceReference ref : departures) {
+ onServiceDeparture(ref);
+ // Notify service unbinding to listeners
+ notifyListeners(DependencyEventType.UNBINDING, ref, m_serviceObjects.get(ref).service);
+ }
+ } finally {
+ releaseReadLockIfHeld();
+ }
+
+
+ }
+
+ /**
+ * Sets the optionality attribute of the current dependency.
+ *
+ * @param isOptional the new optional attribute value.
+ */
+ public void setOptionality(boolean isOptional) {
+ try {
+ acquireWriteLockIfNotHeld();
+ m_optional = isOptional;
+ computeAndSetDependencyState();
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ public boolean isOptional() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_optional;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+ }
+
+ /**
+ * Gets the used binding policy.
+ *
+ * @return the current binding policy.
+ */
+ public int getBindingPolicy() {
+ try {
+ acquireReadLockIfNotHeld();
+ return m_policy;
+ } finally {
+ releaseReadLockIfHeld();
+ }
+
+ }
+
+ /**
+ * Gets the used comparator name.
+ * <code>null</code> if no comparator (i.e. the OSGi one is used).
+ *
+ * @return the comparator class name or <code>null</code> if the dependency doesn't use a comparator.
+ */
+ public String getComparator() {
+ final Comparator<ServiceReference> comparator;
+ try {
+ acquireReadLockIfNotHeld();
+ comparator = m_serviceReferenceManager.getComparator();
+ } finally {
+ releaseReadLockIfHeld();
+ }
+
+ if (comparator != null) {
+ return comparator.getClass().getName();
+ } else {
+ return null;
+ }
+ }
+
+ public void setComparator(Comparator<ServiceReference> cmp) {
+ try {
+ acquireWriteLockIfNotHeld();
+ m_serviceReferenceManager.setComparator(cmp);
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ /**
+ * Sets the bundle context used by this dependency.
+ * This operation is not supported if the tracker is already opened, and as a consequence does not require locking.
+ *
+ * @param context the bundle context or service context to use
+ */
+ public void setBundleContext(BundleContext context) {
+ if (m_tracker == null) { // Not started ...
+ m_context = context;
+ } else {
+ throw new UnsupportedOperationException("Dynamic bundle (i.e. service) context change is not supported");
+ }
+ }
+
+ /**
+ * Gets a service object for the given reference.
+ * The service object is stored to handle custom policies.
+ *
+ * @param ref the wanted service reference
+ * @return the service object attached to the given reference
+ */
+ public Object getService(ServiceReference ref) {
+ return getService(ref, true);
+ }
+
+ /**
+ * Gets a service object for the given reference.
+ *
+ * @param ref the wanted service reference
+ * @param store enables / disables the storing of the reference.
+ * @return the service object attached to the given reference
+ */
+ public Object getService(ServiceReference ref, boolean store) {
+ if (m_tracker == null) {
+ // The tracker is already closed, we can't access the service anymore.
+ return null;
+ }
+
+ // If we already have the service object, just return it.
+ if (m_serviceObjects.containsKey(ref)) {
+ return m_serviceObjects.get(ref).service;
+ }
+
+ ServiceBindingHolder holder = null;
+ Object svc = m_tracker.getService(ref);
+ IPOJOServiceFactory factory = null;
+
+ if (svc instanceof IPOJOServiceFactory) {
+ factory = (IPOJOServiceFactory) svc;
+ svc = factory.getService(m_instance);
+ }
+ holder = new ServiceBindingHolder(ref, factory, svc);
+
+ svc = m_serviceReferenceManager.weavingServiceBinding(holder);
+
+ if (store) {
+ try {
+ acquireWriteLockIfNotHeld();
+ // The service object may have been modified by the interceptor, update the holder
+ if (svc != holder.service) {
+ m_serviceObjects.put(ref, new ServiceBindingHolder(ref, factory, svc));
+ } else {
+ m_serviceObjects.put(ref, holder);
+ }
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+ return svc;
+ }
+
+ /**
+ * Ungets a used service reference.
+ *
+ * @param ref the reference to unget.
+ */
+ public void ungetService(ServiceReference ref) {
+ m_tracker.ungetService(ref);
+ ServiceBindingHolder sbh;
+ try {
+ acquireWriteLockIfNotHeld();
+ sbh = m_serviceObjects.remove(ref);
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+
+ // Call the callback outside the lock.
+ if (sbh != null && sbh.factory != null) {
+ sbh.factory.ungetService(m_instance, sbh.service);
+ }
+
+ m_serviceReferenceManager.unweavingServiceBinding(sbh);
+
+ }
+
+ public ContextSourceManager getContextSourceManager() {
+ // Final member, no lock required.
+ return m_contextSourceManager;
+ }
+
+ /**
+ * Gets the dependency id.
+ *
+ * @return the dependency id. Specification name by default.
+ */
+ public String getId() {
+ // Immutable, no lock required.
+ return getSpecification().getName();
+ }
+
+ /**
+ * Callbacks call by the ServiceReferenceManager when the selected service set has changed.
+ * @param set the change set.
+ */
+ public void onChange(ServiceReferenceManager.ChangeSet set) {
+ try {
+ acquireWriteLockIfNotHeld();
+ // First handle the static case with a frozen state
+ if (isFrozen() && getState() != BROKEN) {
+ for (ServiceReference ref : set.departures) {
+ // Check if any of the service that have left was in used.
+ if (m_boundServices.contains(ref)) {
+ // Static dependency broken.
+ m_state = BROKEN;
+
+ // We are going to call callbacks, releasing the lock.
+ ServiceBindingHolder sbh = m_serviceObjects.get(ref);
+ releaseWriteLockIfHeld();
+
+ // Notify listeners
+ notifyListeners(DependencyEventType.UNBINDING, ref, sbh.service);
+ notifyListeners(DependencyEventType.DEPARTURE, ref, null);
+
+ invalidate(); // This will invalidate the instance.
+ m_instance.stop(); // Stop the instance
+ unfreeze();
+ m_instance.start();
+ return;
+ }
+ }
+ }
+
+ List<ServiceReference> arrivals = new ArrayList<ServiceReference>();
+ List<ServiceReference> departures = new ArrayList<ServiceReference>();
+
+ // Manage departures
+ // We unbind all bound services that are leaving.
+ for (ServiceReference ref : set.departures) {
+ if (m_boundServices.contains(ref)) {
+ // We were using the reference
+ m_boundServices.remove(ref);
+ departures.add(ref);
+ }
+ }
+
+ // Manage arrivals
+ // For aggregate dependencies, call onServiceArrival for all services not-yet-bound and in the order of the
+ // selection.
+ if (m_aggregate) {
+ // If the dependency is not already in used,
+ // the bindings must be sorted as in set.selected
+ if (m_serviceObjects.isEmpty() || DYNAMIC_PRIORITY_BINDING_POLICY == getBindingPolicy()) {
+ m_boundServices.clear();
+ m_boundServices.addAll(set.selected);
+ }
+
+ // Now we notify from the arrival.
+ // If we didn't add the reference yet, we add it.
+ for (ServiceReference ref : set.arrivals) {
+ // We bind all not-already bound services, so it's an arrival
+ if (!m_boundServices.contains(ref)) {
+ m_boundServices.add(ref);
+ }
+ arrivals.add(ref);
+ }
+ } else {
+ if (!set.selected.isEmpty()) {
+ final ServiceReference best = set.selected.get(0);
+ // We have a provider
+ if (m_boundServices.isEmpty()) {
+ // We are not bound with anyone yet, so take the first of the selected set
+ m_boundServices.add(best);
+ arrivals.add(best);
+ } else {
+ final ServiceReference current = m_boundServices.get(0);
+ // We are already bound, to the rebinding decision depends on the binding strategy
+ if (getBindingPolicy() == DYNAMIC_PRIORITY_BINDING_POLICY) {
+ // Rebinding in the DP binding policy if the bound one if not the new best one.
+ if (current != best) {
+ m_boundServices.remove(current);
+ m_boundServices.add(best);
+ departures.add(current);
+ arrivals.add(best);
+ }
+ } else {
+ // In static and dynamic binding policy, if the service is not yet used and the new best is not
+ // the currently selected one, we should switch.
+ boolean isUsed = m_serviceObjects.containsKey(current);
+ if (!isUsed && current != best) {
+ m_boundServices.remove(current);
+ m_boundServices.add(best);
+ departures.add(current);
+ arrivals.add(best);
+ }
+ }
+ }
+ }
+ }
+
+ // Before leaving the protected region, copy used services.
+ Map<ServiceReference, ServiceBindingHolder> services = new HashMap<ServiceReference, ServiceBindingHolder>(m_serviceObjects);
+
+ // Leaving the locked region to invoke callbacks
+ releaseWriteLockIfHeld();
+
+ for (ServiceReference ref : departures) {
+ onServiceDeparture(ref);
+ // Notify service unbinding to listeners
+ final ServiceBindingHolder sbh = services.get(ref);
+ if (sbh != null) {
+ notifyListeners(DependencyEventType.UNBINDING, ref, sbh.service);
+ } else {
+ notifyListeners(DependencyEventType.UNBINDING, ref, null);
+ }
+ // Unget the service reference.
+ ungetService(ref);
+ }
+ for (ServiceReference ref : arrivals) {
+ onServiceArrival(ref);
+ // Notify service binding to listeners
+ final ServiceBindingHolder sbh = services.get(ref);
+ if (sbh != null) {
+ notifyListeners(DependencyEventType.BINDING, ref, sbh.service);
+ } else {
+ notifyListeners(DependencyEventType.BINDING, ref, null);
+ }
+ }
+ // Do we have a modified service ?
+ if (set.modified != null && m_boundServices.contains(set.modified)) {
+ onServiceModification(set.modified);
+ // TODO call boundServiceModified on listeners???
+ }
+
+ // Did our state changed ?
+ // this method will manage its own synchronization.
+ computeAndSetDependencyState();
+ } finally {
+ releaseWriteLockIfHeld();
+ }
+ }
+
+ public ServiceReferenceManager getServiceReferenceManager() {
+ return m_serviceReferenceManager;
+ }
+
+ public Tracker getTracker() {
+ return m_tracker;
+ }
+
+ public enum DependencyEventType {
+ VALIDATE,
+ INVALIDATE,
+ ARRIVAL,
+ MODIFIED,
+ DEPARTURE,
+ BINDING,
+ UNBINDING,
+ RECONFIGURED
+ }
+
+ /**
+ * Add the given listener to the dependency model's list of listeners.
+ *
+ * @param listener the {@code DependencyModelListener} object to be added
+ * @throws NullPointerException if {@code listener} is {@code null}
+ */
+ public void addListener(DependencyModelListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("null listener");
+ }
+ synchronized (m_listeners) {
+ m_listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the given listener from the dependency model's list of listeners.
+ *
+ * @param listener the {@code DependencyModelListener} object to be removed
+ * @throws NullPointerException if {@code listener} is {@code null}
+ * @throws NoSuchElementException if {@code listener} wasn't present in the dependency model's list of listeners
+ */
+ public void removeListener(DependencyModelListener listener) {
+ if (listener == null) {
+ throw new NullPointerException("null listener");
+ }
+ synchronized (m_listeners) {
+ // We definitely cannot rely on listener's equals method...
+ // ...so we need to manually search for the listener, using ==.
+ int i = -1;
+ for(int j = m_listeners.size() -1; j>=0 ; j--) {
+ if (m_listeners.get(j) == listener) {
+ // Found!
+ i = j;
+ break;
+ }
+ }
+ if (i != -1) {
+ m_listeners.remove(i);
+ } else {
+ throw new NoSuchElementException("no such listener");
+ }
+ }
+ }
+
+ /**
+ * Notify all listeners that a change has occurred in this dependency model.
+ *
+ * @param type the type of event
+ * @param service the reference of the concerned service (may be null)
+ * @param object the concerned service object (may be null)
+ */
+ public void notifyListeners(DependencyEventType type, ServiceReference<?> service, Object object) {
+ // Get a snapshot of the listeners
+ List<DependencyModelListener> tmp;
+ synchronized (m_listeners) {
+ tmp = new ArrayList<DependencyModelListener>(m_listeners);
+ }
+ // Do notify, outside the m_listeners lock
+ for (DependencyModelListener l : tmp) {
+ try {
+ switch (type) {
+ case VALIDATE:
+ l.validate(this);
+ break;
+ case INVALIDATE:
+ l.invalidate(this);
+ break;
+ case ARRIVAL:
+ l.matchingServiceArrived(this, service);
+ break;
+ case MODIFIED:
+ l.matchingServiceModified(this, service);
+ break;
+ case DEPARTURE:
+ l.matchingServiceDeparted(this, service);
+ break;
+ case BINDING:
+ l.serviceBound(this, service, object);
+ break;
+ case UNBINDING:
+ l.serviceUnbound(this, service, object);
+ break;
+ case RECONFIGURED:
+ l.reconfigured(this);
+ break;
+ }
+ } catch (Throwable e) {
+ // Put a warning on the logger, and continue
+ getComponentInstance().getFactory().getLogger().log(Log.WARNING,
+ String.format(
+ "[%s] A DependencyModelListener has failed: %s",
+ getComponentInstance().getInstanceName(),
+ e.getMessage())
+ , e);
+ }
+ }
+ }
+
+ /**
+ * Removes all the listeners from this dependency before it gets disposed.
+ */
+ public void cleanup() {
+ synchronized (m_listeners) {
+ m_listeners.clear();
+ }
+ }
+
+ /**
+ * Service binding structure.
+ */
+ public class ServiceBindingHolder {
+
+ public final Object service;
+ public final IPOJOServiceFactory factory;
+ public final ServiceReference reference;
+
+ private ServiceBindingHolder(ServiceReference reference, IPOJOServiceFactory factory, Object service) {
+ this.service = service;
+ this.factory = factory;
+ this.reference = reference;
+ }
+
+ private ServiceBindingHolder(ServiceReference reference, Object service) {
+ this.service = service;
+ this.factory = null;
+ this.reference = reference;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModelListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModelListener.java
new file mode 100644
index 0000000..787900f
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModelListener.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Listener interface for service dependencies of iPOJO component instances.
+ */
+public interface DependencyModelListener extends DependencyStateListener {
+
+ void matchingServiceArrived(DependencyModel dependency, ServiceReference<?> service);
+
+ void matchingServiceModified(DependencyModel dependency, ServiceReference<?> service);
+
+ void matchingServiceDeparted(DependencyModel dependency, ServiceReference<?> service);
+
+ void serviceBound(DependencyModel dependency, ServiceReference<?> service, Object object);
+
+ void serviceUnbound(DependencyModel dependency, ServiceReference<?> service, Object object);
+
+ void reconfigured(DependencyModel dependency);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyStateListener.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyStateListener.java
new file mode 100644
index 0000000..a72409b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyStateListener.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+
+/**
+ * This interface allows a class to be notified of service dependency state changes.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface DependencyStateListener {
+
+ /**
+ * The given dependency becomes valid.
+ * @param dependency the dependency becoming valid.
+ */
+ void validate(DependencyModel dependency);
+
+ /**
+ * The given dependency becomes invalid.
+ * @param dependency the dependency becoming invalid.
+ */
+ void invalidate(DependencyModel dependency);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Fields.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Fields.java
new file mode 100644
index 0000000..3dc5b78
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Fields.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+* Fluent API to retrieve fields of a given type.
+*/
+public class Fields<T> {
+
+ private Class<? extends T> type;
+ private Class<?> clazz;
+ private Object object;
+ private Map<String, Field> fields;
+
+ public Collection<T> get() {
+ return map().values();
+ }
+
+ public Map<Field, T> map(Object o) {
+ this.object = o;
+ return map();
+ }
+
+ public Map<Field, T> map() {
+ Collection<Field> set = retrieve();
+ Map<Field, T> results = new LinkedHashMap<Field, T>();
+ for (Field field : set) {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+
+ try {
+ results.put(field, (T) field.get(object));
+ } catch (IllegalAccessException e) {
+ // Hopefully should not happen.
+ }
+ }
+ return results;
+ }
+
+ public Collection<T> get(Object o) {
+ this.object = o;
+ return get();
+ }
+
+ public Fields ofType(Class<? extends T> clazz) {
+ this.type = clazz;
+ return this;
+ }
+
+ public Fields in(Object o) {
+ this.object = o;
+ this.clazz = o.getClass();
+ return this;
+ }
+
+ public Fields in(Class<?> c) {
+ this.clazz = c;
+ return this;
+ }
+
+ private Collection<Field> retrieve() {
+ if (fields != null) {
+ return fields.values();
+ }
+
+ if (clazz == null) {
+ throw new NullPointerException("Cannot retrieve field, class not set");
+ }
+
+
+ fields = new LinkedHashMap<String, Field>();
+
+ // First the class itself
+ Field[] list = clazz.getDeclaredFields();
+ for (Field field : list) {
+ if (type == null || type.isAssignableFrom(field.getType())) {
+ fields.put(field.getName(), field);
+ }
+ }
+
+ // Traverse class hierarchy
+ if (clazz.getSuperclass() != null) {
+ traverse(fields, clazz.getSuperclass());
+ }
+
+ return fields.values();
+ }
+
+ private void traverse(Map<String, Field> fields, Class<?> clazz) {
+ // First the given class
+ Field[] list = clazz.getDeclaredFields();
+ for (Field field : list) {
+ if (type == null || type.isAssignableFrom(field.getType())) {
+ // Already defined by a daughter class
+ if (!fields.containsKey(field.getName())) {
+ // Check visibility if must be either public or protected.
+ if (Modifier.isPublic(field.getModifiers()) || Modifier.isProtected(field.getModifiers())) {
+ fields.put(field.getName(), field);
+ }
+ }
+ }
+ }
+
+ // If we have a parent class, traverse it
+ if (clazz.getSuperclass() != null) {
+ traverse(fields, clazz.getSuperclass());
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InstanceConfigurationSource.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InstanceConfigurationSource.java
new file mode 100644
index 0000000..4e62572
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InstanceConfigurationSource.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+
+import java.util.*;
+
+/**
+ * A context source giving access to system properties.
+ */
+public class InstanceConfigurationSource implements ContextSource {
+
+ /**
+ * The instance configuration.
+ */
+ private Dictionary<String,Object> m_configuration;
+
+ /**
+ * Listener list.
+ */
+ private List<ContextListener> m_listeners = new ArrayList<ContextListener>();
+
+ public InstanceConfigurationSource(Dictionary<String, Object> configuration) {
+ m_configuration = configuration;
+ }
+
+ /**
+ * The instance is reconfigured.
+ * Changes are computed by comparing the old and new configuration.
+ * @param newConfiguration the new instance configuration
+ */
+ public void reconfigure(Dictionary<String, Object> newConfiguration) {
+ // Copy the current configuration and update the field.
+ Hashtable<String, Object> configuration = new Hashtable<String, Object>();
+ Enumeration<String> enumeration = m_configuration.keys();
+ while (enumeration.hasMoreElements()) {
+ final String key = enumeration.nextElement();
+ configuration.put(key, m_configuration.get(key));
+ }
+ // We now have a copy of the current configuration.
+ // We must set the field to the new configuration, as updates are going to be fired.
+ // so we must have reflected the updates already.
+ m_configuration = newConfiguration;
+
+ // We use the same loop to find lost and updated properties.
+ enumeration = configuration.keys();
+ while (enumeration.hasMoreElements()) {
+ final String key = enumeration.nextElement();
+ final Object newValue = newConfiguration.get(key);
+ final Object oldValue = configuration.get(key);
+ if (newValue == null) {
+ // If we don't have the property anymore, notify the departure.
+ fireUpdate(key, null);
+ } else {
+ // The new configuration still has a value, is it the same ?
+ if (! newValue.equals(oldValue)) {
+ fireUpdate(key, newValue);
+ }
+ }
+ }
+
+ // Do we have new properties ?
+ enumeration = newConfiguration.keys();
+ while (enumeration.hasMoreElements()) {
+ final String key = enumeration.nextElement();
+ if (configuration.get(key) == null) {
+ Object newValue = newConfiguration.get(key);
+ fireUpdate(key, newValue);
+ }
+ }
+ }
+
+ private void fireUpdate(String key, Object newValue) {
+ for (ContextListener listener : m_listeners) {
+ listener.update(this, key, newValue);
+ }
+ }
+
+ public Object getProperty(String property) {
+ return m_configuration.get(property);
+ }
+
+ public Dictionary getContext() {
+ return m_configuration;
+ }
+
+ public void registerContextListener(ContextListener listener, String[] properties) {
+ if (! m_listeners.contains(listener)) {
+ m_listeners.add(listener);
+ }
+ }
+
+ public void unregisterContextListener(ContextListener listener) {
+ m_listeners.remove(listener);
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InvocationResult.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InvocationResult.java
new file mode 100644
index 0000000..96812a5
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/InvocationResult.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Wraps the result of a method invocation
+ */
+public class InvocationResult<T> {
+
+ private final Method method;
+ private final Object target;
+ private final T result;
+ private final Throwable error;
+
+ public InvocationResult(Method method, Object target, T result, Throwable error) {
+ this.method = method;
+ this.target = target;
+ this.result = result;
+ this.error = error;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public Object getTarget() {
+ return target;
+ }
+
+ public Throwable error() {
+ return error;
+ }
+
+ public T get() {
+ return result;
+ }
+
+ public T getOrElse(T def) {
+ if (error == null) {
+ return def;
+ } else {
+ return result;
+ }
+ }
+
+ public static <T> InvocationResult<T> fromInvocation(Method method, Object target, Object[] args) {
+ try {
+ T result = (T) method.invoke(target, args);
+ return new InvocationResult<T>(method, target, result, null);
+ } catch (IllegalAccessException e) {
+ return new InvocationResult<T>(method, target, null, e);
+ } catch (InvocationTargetException e) {
+ return new InvocationResult<T>(method, target, null, e);
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java
new file mode 100644
index 0000000..6bbfe28
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Log.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+/**
+ * API for the iPOJO internal Log system.
+ */
+public interface Log {
+ /**
+ * The Log Level ERROR.
+ */
+ int ERROR = 1;
+ /**
+ * The Log Level WARNING.
+ */
+ int WARNING = 2;
+ /**
+ * The Log Level INFO.
+ */
+ int INFO = 3;
+ /**
+ * The Log Level DEBUG.
+ */
+ int DEBUG = 4;
+
+ void log(int level, String msg);
+
+ void log(int level, String msg, Throwable exception);
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
new file mode 100644
index 0000000..1713e2d
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
@@ -0,0 +1,318 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ErrorHandler;
+import org.apache.felix.ipojo.extender.internal.Extender;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * iPOJO Logger.
+ * This class is an helper class implementing a simple log system.
+ * This logger sends log messages to a log service if available.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Logger implements Log {
+
+ /**
+ * The iPOJO default log level property.
+ */
+ public static final String IPOJO_LOG_LEVEL_PROP = "ipojo.log.level";
+ /**
+ * iPOJO log level manifest header.
+ * The uppercase 'I' is important as BND removes all headers that do not
+ * start with an uppercase are not added to the bundle.
+ * Use an upper case to support bnd.
+ */
+ public static final String IPOJO_LOG_LEVEL_HEADER = "IPOJO-log-level";
+ /**
+ * A shared log service implementation writing messages on the console.
+ */
+ private static final LogService m_defaultLogger = new ConsoleLogService();
+ private static final String DEBUG_HEADER = "[DEBUG]";
+ private static final String INFO_HEADER = "[INFO]";
+ private static final String WARNING_HEADER = "[WARNING]";
+ private static final String ERROR_HEADER = "[ERROR]";
+ private static final String UNKNOWN_HEADER = "[UNKNOWN]";
+ /**
+ * The Bundle Context used to get the
+ * log service.
+ */
+ private final BundleContext m_context;
+ /**
+ * The name of the logger.
+ */
+ private final String m_name;
+ /**
+ * The trace level of this logger.
+ */
+ private final int m_level;
+ /**
+ * The instance associated to the logger if any.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Creates a logger.
+ *
+ * @param context the bundle context
+ * @param name the name of the logger
+ * @param level the trace level
+ */
+ public Logger(BundleContext context, String name, int level) {
+ m_name = name;
+ m_level = level;
+ m_context = context;
+ }
+
+ /**
+ * Creates a logger.
+ *
+ * @param context the bundle context
+ * @param instance the instance
+ * @param level the trace level
+ */
+ public Logger(BundleContext context, ComponentInstance instance, int level) {
+ this(context, instance.getInstanceName(), level);
+ m_instance = instance;
+ }
+
+ /**
+ * Create a logger.
+ * Uses the default logger level.
+ *
+ * @param context the bundle context
+ * @param name the name of the logger
+ */
+ public Logger(BundleContext context, String name) {
+ this(context, name, getDefaultLevel(context));
+ }
+
+ /**
+ * Create a logger.
+ * Uses the default logger level.
+ *
+ * @param context the bundle context
+ * @param instance the instance
+ */
+ public Logger(BundleContext context, ComponentInstance instance) {
+ this(context, instance, getDefaultLevel(context));
+ }
+
+ /**
+ * Gets the default logger level.
+ * The property is searched inside the framework properties,
+ * the system properties, and in the manifest from the given
+ * bundle context. By default, set the level to {@link Logger#WARNING}.
+ *
+ * @param context the bundle context.
+ * @return the default log level.
+ */
+ private static int getDefaultLevel(BundleContext context) {
+ // First check in the framework and in the system properties
+ String level = context.getProperty(IPOJO_LOG_LEVEL_PROP);
+
+ // If null, look in the bundle manifest
+ if (level == null) {
+ String key = IPOJO_LOG_LEVEL_PROP.replace('.', '-');
+ level = (String) context.getBundle().getHeaders().get(key);
+ }
+
+ // if still null try the second header
+ if (level == null) {
+ level = (String) context.getBundle().getHeaders().get(IPOJO_LOG_LEVEL_HEADER);
+ }
+
+ if (level != null) {
+ if (level.equalsIgnoreCase("info")) {
+ return INFO;
+ } else if (level.equalsIgnoreCase("debug")) {
+ return DEBUG;
+ } else if (level.equalsIgnoreCase("warning")) {
+ return WARNING;
+ } else if (level.equalsIgnoreCase("error")) {
+ return ERROR;
+ }
+ }
+
+ // Either l is null, either the specified log level was unknown
+ // Set the default to WARNING
+ return WARNING;
+
+ }
+
+ private static String getLogHeaderForLevel(int level) {
+ switch (level) {
+ case DEBUG:
+ return DEBUG_HEADER;
+ case INFO:
+ return INFO_HEADER;
+ case WARNING:
+ return WARNING_HEADER;
+ case ERROR:
+ return ERROR_HEADER;
+ default:
+ return UNKNOWN_HEADER;
+ }
+ }
+
+ /**
+ * Logs a message.
+ *
+ * @param level the level of the message
+ * @param msg the the message to log
+ */
+ public void log(int level, String msg) {
+ if (m_level >= level) {
+ dispatch(level, msg, null);
+ }
+ invokeErrorHandler(level, msg, null);
+ }
+
+ /**
+ * Logs a message with an exception.
+ *
+ * @param level the level of the message
+ * @param msg the message to log
+ * @param exception the exception attached to the message
+ */
+ public void log(int level, String msg, Throwable exception) {
+ if (m_level >= level) {
+ dispatch(level, msg, exception);
+ }
+ invokeErrorHandler(level, msg, exception);
+ }
+
+ /**
+ * Internal log method.
+ *
+ * @param level the level of the message.
+ * @param msg the message to log
+ * @param exception the exception attached to the message
+ */
+ private void dispatch(int level, String msg, Throwable exception) {
+ LogService log = null;
+ ServiceReference ref = null;
+ try {
+ // Security Check
+ if (SecurityHelper.hasPermissionToGetService(LogService.class.getName(), m_context)) {
+ ref = m_context.getServiceReference(LogService.class.getName());
+ } else {
+ Extender.getIPOJOBundleContext().getServiceReference(LogService.class.getName());
+ }
+
+ if (ref != null) {
+ log = (LogService) m_context.getService(ref);
+ }
+ } catch (IllegalStateException e) {
+ // Handle the case where the iPOJO bundle is stopping, or the log service already ran away.
+ }
+
+ if (log == null) {
+ log = m_defaultLogger;
+ }
+
+ String name = m_name;
+ if (name == null) {
+ name = "";
+ }
+
+ String message = String.format("%s %s : %s", getLogHeaderForLevel(level), name, msg);
+ switch (level) {
+ case DEBUG:
+ log.log(LogService.LOG_DEBUG, message, exception);
+ break;
+ case INFO:
+ log.log(LogService.LOG_INFO, message, exception);
+ break;
+ case WARNING:
+ log.log(LogService.LOG_WARNING, message, exception);
+ break;
+ case ERROR:
+ log.log(LogService.LOG_ERROR, message, exception);
+ break;
+ default:
+ log.log(LogService.LOG_INFO, message, exception);
+ break;
+ }
+
+ if (ref != null) {
+ m_context.ungetService(ref);
+ }
+ }
+
+ /**
+ * Invokes the error handler service is present.
+ *
+ * @param level the log level
+ * @param msg the message
+ * @param error the error
+ */
+ private void invokeErrorHandler(int level, String msg, Throwable error) {
+ // First check the level
+ if (level > WARNING) {
+ return; // Others levels are not supported.
+ }
+ // Try to get the error handler service
+ try {
+ ServiceReference ref = m_context.getServiceReference(ErrorHandler.class.getName());
+ if (ref != null) {
+ ErrorHandler handler = (ErrorHandler) m_context.getService(ref);
+ if (level == ERROR) {
+ handler.onError(m_instance, msg, error);
+ } else if (level == WARNING) {
+ handler.onWarning(m_instance, msg, error);
+ } // The others case are not supported
+ m_context.ungetService(ref);
+ } // Else do nothing...
+ } catch (IllegalStateException e) {
+ // Ignore
+ // The iPOJO bundle is stopping.
+ }
+ }
+
+ /**
+ * A simple log service implementation writing the messages and stack trace on System.err.
+ */
+ private static class ConsoleLogService implements LogService {
+
+ public void log(int i, String s) {
+ log(i, s, null);
+ }
+
+ public void log(int level, String message, Throwable exception) {
+ System.err.println(message);
+ if (exception != null) {
+ exception.printStackTrace();
+ }
+ }
+
+ public void log(ServiceReference serviceReference, int i, String s) {
+ // not used.
+ }
+
+ public void log(ServiceReference serviceReference, int i, String s, Throwable throwable) {
+ // not used.
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Methods.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Methods.java
new file mode 100644
index 0000000..d25d02c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Methods.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * Fluent API to retrieve methods.
+ */
+public class Methods<T> {
+
+ private Class<? extends T> returnType;
+ private List<Class<?>> argumentTypes = new ArrayList<Class<?>>();
+ private Class<?> clazz;
+ private Object object;
+ private List<Method> methods;
+
+ public Map<Method, InvocationResult<T>> map(Object... args) {
+ Collection<Method> set = retrieve();
+ Map<Method, InvocationResult<T>> results = new LinkedHashMap<Method, InvocationResult<T>>();
+ for (Method method : set) {
+ if (!method.isAccessible()) {
+ method.setAccessible(true);
+ }
+
+ results.put(method, InvocationResult.<T>fromInvocation(method, object, args));
+
+ }
+ return results;
+ }
+
+ public Collection<InvocationResult<T>> invoke(Object... args) {
+ return map(args).values();
+ }
+
+ public Methods ofReturnType(Class<? extends T> clazz) {
+ this.returnType = clazz;
+ return this;
+ }
+
+ public Methods withParameter(Class<?>... type) {
+ argumentTypes.addAll(Arrays.asList(type));
+ return this;
+ }
+
+ public Methods in(Object o) {
+ this.object = o;
+ this.clazz = o.getClass();
+ return this;
+ }
+
+ public Methods in(Class<?> c) {
+ this.clazz = c;
+ this.object = null;
+ return this;
+ }
+
+ private Collection<Method> retrieve() {
+ if (methods != null) {
+ return methods;
+ }
+
+ if (clazz == null) {
+ throw new NullPointerException("Cannot retrieve method, class not set");
+ }
+
+
+ methods = new ArrayList<Method>();
+
+ // First the class itself
+ Method[] list = clazz.getDeclaredMethods();
+ for (Method method : list) {
+ // Two criteria : the return type and the argument type
+ if (matchReturnType(method)
+ && matchArgumentTypes(method)) {
+ // The method matches
+ methods.add(method);
+ }
+ }
+
+ // Traverse class hierarchy
+ if (clazz.getSuperclass() != null) {
+ traverse(methods, clazz.getSuperclass());
+ }
+
+ return methods;
+ }
+
+ private boolean matchReturnType(Method method) {
+ if (returnType == null) { // Void.
+ return method.getReturnType() == null;
+ }
+
+ return !(method.getReturnType() == null || !returnType.isAssignableFrom(method.getReturnType()));
+ }
+
+ private boolean matchArgumentTypes(Method method) {
+ // Fast check, the size must be the same.
+ if (argumentTypes.size() != method.getParameterTypes().length) {
+ return false;
+ }
+
+ // We have the same size.
+ for (int i = 0; i < argumentTypes.size(); i++) {
+ Class<?> argType = method.getParameterTypes()[i];
+ if (!argumentTypes.get(i).isAssignableFrom(argType)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean matchInheritanceVisibility(Method method) {
+ return Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers());
+ }
+
+ private boolean matchNotOverridden(Method method, List<Method> methods) {
+ for (Method meth : methods) {
+ if (methodEquality(meth, method)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Compares this <code>Method</code> against the specified object. Returns
+ * true if the objects are the same. Two <code>Methods</code> are the same if
+ * they were declared by the same class and have the same name
+ * and formal parameter types and return type.
+ */
+ private boolean methodEquality(Method method1, Method method2) {
+ if (method1.getName().equals(method2.getName())) {
+ if (!method1.getReturnType().equals(method2.getReturnType())) {
+ return false;
+ }
+
+ Class[] params1 = method1.getParameterTypes();
+ Class[] params2 = method2.getParameterTypes();
+ if (params1.length == params2.length) {
+ for (int i = 0; i < params1.length; i++) {
+ if (params1[i] != params2[i])
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ return false;
+ }
+
+ private void traverse(List<Method> methods, Class<?> clazz) {
+ // First the given class
+ Method[] list = clazz.getDeclaredMethods();
+ for (Method method : list) {
+ if (matchReturnType(method) && matchArgumentTypes(method) && matchInheritanceVisibility(method)
+ && matchNotOverridden(method, methods)) {
+ methods.add(method);
+ }
+ }
+
+ // If we have a parent class, traverse it
+ if (clazz.getSuperclass() != null) {
+ traverse(methods, clazz.getSuperclass());
+ }
+ }
+
+}
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
new file mode 100644
index 0000000..0ebc880
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Property.java
@@ -0,0 +1,689 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.ConstructorInjector;
+import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Property class managing a managed value.
+ * This class managed the method invocation, field injection
+ * and constructor injection.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Property implements FieldInterceptor, ConstructorInjector {
+
+ /**
+ * Object used for an unvalued property.
+ */
+ 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.
+ */
+ private final String m_name;
+
+ /**
+ * The field of the property.
+ * Cannot change once set.
+ */
+ private final String m_field;
+
+ /**
+ * The setter method of the property.
+ * Cannot change once set.
+ */
+ private final Callback m_method;
+
+ /**
+ * The index of the parameter in case of
+ * constructor injection.
+ */
+ private int m_index = -1;
+
+ /**
+ * The value of the property.
+ */
+ private Object m_value = NO_VALUE;
+
+ /**
+ * The default value of the property.
+ */
+ private Object m_defaultValue = NO_VALUE;
+
+ /**
+ * Flag tracking is the method was
+ * already called for the current value.
+ */
+ private boolean m_invoked;
+
+ /**
+ * The type of the property.
+ */
+ private final Class m_type;
+
+ /**
+ * The handler object to get the logger.
+ */
+ private final Handler m_handler;
+
+ /**
+ * The instance manager.
+ */
+ private final InstanceManager m_manager;
+
+ /**
+ * Creates a property.
+ * At least the method or the field need
+ * to be specified.
+ * @param name the name of the property (optional)
+ * @param field the name of the field
+ * @param method the method name
+ * @param value the initial value of the property (optional)
+ * @param type the the type of the property
+ * @param manager the instance manager
+ * @param handler the handler object which manage this property.
+ * @throws ConfigurationException if the property value cannot be set.
+ */
+ public Property(String name, String field, String method, String value, String type, InstanceManager manager, Handler handler) throws ConfigurationException {
+ m_handler = handler;
+ m_manager = manager;
+ m_field = field;
+
+ if (name == null) {
+ if (m_field == null) {
+ m_name = method;
+ } else {
+ m_name = field;
+ }
+ } else {
+ m_name = name;
+ }
+
+ m_type = computeType(type, manager.getGlobalContext());
+ if (value != null) {
+ m_value = create(m_type, value);
+ m_defaultValue = m_value;
+ }
+
+ if (method != null) {
+ m_method = new Callback(method, new String[] { m_type.getName() }, false, manager);
+ } else {
+ m_method = null;
+ }
+ }
+
+ /**
+ * Creates a property.
+ * At least the method or the field need
+ * to be specified.
+ * @param name the name of the property (optional)
+ * @param field the name of the field
+ * @param method the method name
+ * @param value the initial value of the property (optional)
+ * @param manager the instance manager
+ * @param handler the handler object which manage this property.
+ * @throws ConfigurationException if the property value cannot be set.
+ */
+ public Property(String name, String field, String method, Object value, InstanceManager manager, Handler handler) throws ConfigurationException {
+ m_handler = handler;
+ m_manager = manager;
+ m_field = field;
+
+ if (value == null) {
+ throw new ConfigurationException("Cannot create properties without a value");
+ }
+
+ if (name == null) {
+ if (m_field == null) {
+ m_name = method;
+ } else {
+ m_name = field;
+ }
+ } else {
+ m_name = name;
+ }
+
+ m_type = value.getClass();
+ m_value = value;
+ m_defaultValue = m_value;
+
+ if (method != null) {
+ m_method = new Callback(method, new String[] { m_type.getName() }, false, manager);
+ } else {
+ m_method = null;
+ }
+ }
+
+ public Property(String name, String field, String method, int index,
+ String value, String type, InstanceManager manager, Handler handler) throws ConfigurationException {
+ this(name, field, method, value, type, manager, handler);
+ m_index = index;
+ }
+
+ /**
+ * Computes and returns the property type according to the given type name.
+ * @param type the the type name
+ * @param context the bundle context (used to load classes)
+ * @return the class of the given type
+ * @throws ConfigurationException if an error occurs when loading the type class for non-primitive types.
+ */
+ public static Class computeType(String type, BundleContext context) throws ConfigurationException {
+ // Array :
+ if (type.endsWith("[]")) {
+ return computeArrayType(type, context);
+ } else {
+ // Syntactic sugar to avoid writing java.lang.String
+ if ("string".equals(type) || "String".equals(type)) {
+ return java.lang.String.class;
+ } else if ("boolean".equals(type)) {
+ return Boolean.TYPE;
+ } else if ("byte".equals(type)) {
+ return Byte.TYPE;
+ } else if ("short".equals(type)) {
+ return Short.TYPE;
+ } else if ("int".equals(type)) {
+ return Integer.TYPE;
+ } else if ("long".equals(type)) {
+ return Long.TYPE;
+ } else if ("float".equals(type)) {
+ return Float.TYPE;
+ } else if ("double".equals(type)) {
+ return Double.TYPE;
+ } else if ("char".equals(type)) {
+ return Character.TYPE;
+ } else {
+ // Non array, complex type.
+ try {
+ return context.getBundle().loadClass(type);
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Class not found exception in setValue on " + type, e);
+ } catch (SecurityException e) {
+ throw new ConfigurationException("Security exception in setValue on " + type, e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Argument issue when calling the constructor of the type " + type, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the Class object of a type array.
+ * @param type the string descriptor of the type (must end by [] )
+ * @param context the bundle context (used to load classes)
+ * @return the Class object of the given type array.
+ * @throws ConfigurationException if the class cannot be loaded
+ */
+ private static Class computeArrayType(String type, BundleContext context) throws ConfigurationException {
+ // Note: Harmony does't support the type[].class notation.
+ // An empty array has to be created to get the class object.
+ String internalType = type.substring(0, type.length() - 2);
+ if ("string".equals(internalType) || "String".equals(internalType)) {
+ return new String[0].getClass();
+ }
+ if ("boolean".equals(internalType)) {
+ return new boolean[0].getClass();
+ }
+ if ("byte".equals(internalType)) {
+ return new byte[0].getClass();
+ }
+ if ("short".equals(internalType)) {
+ return new short[0].getClass();
+ }
+ if ("int".equals(internalType)) {
+ return new int[0].getClass();
+ }
+ if ("long".equals(internalType)) {
+ return new long[0].getClass();
+ }
+ if ("float".equals(internalType)) {
+ return new float[0].getClass();
+ }
+ if ("double".equals(internalType)) {
+ return new double[0].getClass();
+ }
+ if ("char".equals(internalType)) {
+ return new char[0].getClass();
+ }
+
+ // Complex array type.
+ try {
+ Class clazz = context.getBundle().loadClass(internalType);
+ Object[] object = (Object[]) Array.newInstance(clazz, 0);
+ return object.getClass();
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Class not found exception in setValue on " + internalType, e);
+ } catch (SecurityException e) {
+ throw new ConfigurationException("Security Exception in setValue on " + internalType, e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Argument issue when calling the constructor of the type " + internalType, e);
+ }
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public String getField() {
+ return m_field;
+ }
+
+ public String getType() {
+ return m_type.getName();
+ }
+
+ /**
+ * Gets the method name,
+ * <code>null</code> if no method.
+ * @return the method name.
+ */
+ public String getMethod() {
+ if (m_method == null) { return null; }
+ return m_method.getMethod();
+ }
+
+ /**
+ * Checks if the property has a method callback.
+ * @return <code>true</code> if the property has a method.
+ */
+ public boolean hasMethod() {
+ return m_method != null;
+ }
+
+ /**
+ * Gets the parameter index.
+ * @return the parameter index or <code>-1</code>
+ * if this property is not injected using constructor
+ * parameter.
+ */
+ public int getParameterIndex() {
+ return m_index;
+ }
+
+ /**
+ * Checks if the property has a field.
+ * @return <code>true</code> if the property has a field.
+ */
+ public boolean hasField() {
+ return m_field != null;
+ }
+
+ public synchronized Object getValue() {
+ return m_value;
+ }
+
+ /**
+ * Gets the initial value of the property.
+ * @return the default value.
+ */
+ public Object getDefaultValue() {
+ return m_defaultValue;
+ }
+
+ /**
+ * Gets the NO VALUE Object.
+ * This method returns the object to inject when the property
+ * was not assigned to a value.
+ * @param type the type of the value.
+ * @return the object to inject when the property has no value.
+ */
+ private static Object getNoValue(Class type) {
+ if (Boolean.TYPE.equals(type)) { return Boolean.FALSE; }
+ if (Byte.TYPE.equals(type)) { return new Byte((byte) 0); }
+ if (Short.TYPE.equals(type)) { return new Short((short) 0); }
+ if (Integer.TYPE.equals(type)) { return new Integer(0); }
+ if (Long.TYPE.equals(type)) { return new Long(0); }
+ if (Float.TYPE.equals(type)) { return new Float(0); }
+ if (Double.TYPE.equals(type)) { return new Double(0); }
+ if (Character.TYPE.equals(type)) { return new Character((char) 0); }
+ // If all other case, return null.
+ return null;
+ }
+
+ /**
+ * Sets the value of the property.
+ * @param value the new value.
+ */
+ public void setValue(Object value) {
+ synchronized (this) {
+ // Is the object is directly assignable to the property, affect it.
+ if (isAssignable(m_type, value)) {
+ m_value = value;
+ } else {
+ // If the object is a String, we must recreate the object from the String form
+ if (value instanceof String) {
+ try {
+ m_value = create(m_type, (String) value);
+ } catch (ConfigurationException e) {
+ throw new ClassCastException("Incompatible type for the property " + m_name + " : " + e.getMessage());
+ }
+ } else {
+ // Error, the given property cannot be injected.
+ throw new ClassCastException("Incompatible type for the property " + m_name + " " + m_type.getName() + " expected, "
+ + value.getClass() + " found");
+ }
+ }
+ m_invoked = false;
+ }
+ }
+
+ /**
+ * Checks if the given value is assignable to the given type.
+ * @param type the class of the type
+ * @param value the object to check
+ * @return <code>true</code> if the object is assignable in the property of type 'type'.
+ */
+ public static boolean isAssignable(Class type, Object value) {
+ if (value == null || type.isInstance(value) || value == Property.NO_VALUE) { // When the value is null, the assign works necessary.
+ return true;
+ } else if (type.isPrimitive()) {
+ // Manage all boxing types.
+ if (value instanceof Boolean && Boolean.TYPE.equals(type)) { return true; }
+ if (value instanceof Byte && Byte.TYPE.equals(type)) { return true; }
+ if (value instanceof Short && Short.TYPE.equals(type)) { return true; }
+ if (value instanceof Integer && Integer.TYPE.equals(type)) { return true; }
+ if (value instanceof Long && Long.TYPE.equals(type)) { return true; }
+ if (value instanceof Float && Float.TYPE.equals(type)) { return true; }
+ if (value instanceof Double && Double.TYPE.equals(type)) { return true; }
+ if (value instanceof Character && Character.TYPE.equals(type)) { return true; }
+ return false;
+ } else {
+ // Else return false.
+ return false;
+ }
+ }
+
+ /**
+ * Creates an object of the given type with the given String value.
+ * @param type the type of the returned object
+ * @param strValue the String value.
+ * @return the object of type 'type' created from the String 'value'
+ * @throws ConfigurationException if the object cannot be created.
+ */
+ public static Object create(Class type, String strValue) throws ConfigurationException {
+ if (Boolean.TYPE.equals(type)) {
+ return Boolean.valueOf(strValue);
+ }
+ if (Byte.TYPE.equals(type)) { return new Byte(strValue); }
+ if (Short.TYPE.equals(type)) { return new Short(strValue); }
+ if (Integer.TYPE.equals(type)) { return new Integer(strValue); }
+ if (Long.TYPE.equals(type)) { return new Long(strValue); }
+ if (Float.TYPE.equals(type)) { return new Float(strValue); }
+ if (Double.TYPE.equals(type)) { return new Double(strValue); }
+ // Character is a bit tricky, it's a boxing type, but there is not creator taking a String as parameter.
+ if (Character.TYPE.equals(type) || Character.class.equals(type)) { return strValue.charAt(0); }
+
+ // Array :
+ if (type.isArray()) {
+ return createArrayObject(type.getComponentType(), ParseUtils.parseArrays(strValue));
+ }
+
+ // Enum :
+ if (type.getSuperclass() != null && type.getSuperclass().getName().equals("java.lang.Enum")) {
+ try {
+ Method valueOf = type.getMethod("valueOf", new Class[] {String.class});
+ if (! valueOf.isAccessible()) {
+ valueOf.setAccessible(true);
+ }
+ // Invoke the static method
+ return valueOf.invoke(null, new String[] {strValue});
+ } catch (InvocationTargetException e) {
+ throw new ConfigurationException("Cannot create an enumerated value for " + type
+ + " with " + strValue, e.getTargetException());
+ } catch (Exception e) {
+ throw new ConfigurationException("Cannot create an enumerated value for " + type
+ + " with " + strValue, e);
+ }
+ }
+
+ // Else it is a neither a primitive type neither a String -> create
+ // the object by calling a constructor with a string in argument.
+ try {
+ Constructor cst = type.getConstructor(new Class[] { String.class });
+ return cst.newInstance(new Object[] { strValue });
+ } catch (SecurityException e) {
+ throw new ConfigurationException("Security exception during the creation of " + type, e);
+ } catch (NoSuchMethodException e) {
+ throw new ConfigurationException("Constructor not found exception during the creation of " + type, e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Argument issue when calling the constructor of the type " + type, e);
+ } catch (InstantiationException e) {
+ throw new ConfigurationException("Instantiation problem " + type, e);
+ } catch (IllegalAccessException e) {
+ throw new ConfigurationException("Illegal Access " + type, e);
+ } catch (InvocationTargetException e) {
+ throw new ConfigurationException("Invocation problem during the creation of " + type, e.getTargetException());
+ }
+
+ }
+
+ /**
+ * Creates an array object containing the type component type from
+ * the String array 'values'.
+ * @param interntype the internal type of the array.
+ * @param values the String array
+ * @return the array containing objects created from the 'values' array
+ * @throws ConfigurationException if the array cannot be created correctly
+ */
+ public static Object createArrayObject(Class interntype, String[] values) throws ConfigurationException {
+ if (Boolean.TYPE.equals(interntype)) {
+ boolean[] bool = new boolean[values.length];
+ for (int i = 0; i < values.length; i++) {
+ bool[i] = Boolean.valueOf(values[i]).booleanValue();
+ }
+ return bool;
+ }
+ if (Byte.TYPE.equals(interntype)) {
+ byte[] byt = new byte[values.length];
+ for (int i = 0; i < values.length; i++) {
+ byt[i] = new Byte(values[i]).byteValue();
+ }
+ return byt;
+ }
+ if (Short.TYPE.equals(interntype)) {
+ short[] shor = new short[values.length];
+ for (int i = 0; i < values.length; i++) {
+ shor[i] = new Short(values[i]).shortValue();
+ }
+ return shor;
+ }
+ if (Integer.TYPE.equals(interntype)) {
+ int[] ints = new int[values.length];
+ for (int i = 0; i < values.length; i++) {
+ ints[i] = new Integer(values[i]).intValue();
+ }
+ return ints;
+ }
+ if (Long.TYPE.equals(interntype)) {
+ long[] longs = new long[values.length];
+ for (int i = 0; i < values.length; i++) {
+ longs[i] = new Long(values[i]).longValue();
+ }
+ return longs;
+ }
+ if (Float.TYPE.equals(interntype)) {
+ float[] floats = new float[values.length];
+ for (int i = 0; i < values.length; i++) {
+ floats[i] = new Float(values[i]).floatValue();
+ }
+ return floats;
+ }
+ if (Double.TYPE.equals(interntype)) {
+ double[] doubles = new double[values.length];
+ for (int i = 0; i < values.length; i++) {
+ doubles[i] = new Double(values[i]).doubleValue();
+ }
+ return doubles;
+ }
+ if (Character.TYPE.equals(interntype)) {
+ char[] chars = new char[values.length];
+ for (int i = 0; i < values.length; i++) {
+ chars[i] = values[i].toCharArray()[0];
+ }
+ return chars;
+ }
+
+ // Else it is a neither a primitive type -> create the
+ // object by calling a constructor with a string in argument.
+ try {
+ Constructor cst = interntype.getConstructor(new Class[] { String.class });
+ Object[] object = (Object[]) Array.newInstance(interntype, values.length);
+ for (int i = 0; i < values.length; i++) {
+ object[i] = cst.newInstance(new Object[] { values[i].trim() });
+ }
+ return object;
+ } catch (NoSuchMethodException e) {
+ throw new ConfigurationException("Constructor not found exception in setValue on " + interntype.getName(), e);
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException("Argument issue when calling the constructor of the type " + interntype.getName(), e);
+ } catch (InstantiationException e) {
+ throw new ConfigurationException("Instantiation problem " + interntype.getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ConfigurationException("Illegal Access Exception in " + interntype.getName(), e);
+ } catch (InvocationTargetException e) {
+ throw new ConfigurationException("Invocation problem " + interntype.getName(), e.getTargetException());
+ }
+ }
+
+ /**
+ * Clears the invoked flag.
+ * Then, despite the setter was already called,
+ * it will be invoked another times.
+ */
+ public synchronized void reset() {
+ m_invoked = false;
+ }
+
+ /**
+ * Invokes the setter method on the given pojo object.
+ * If no specified pojo object, it calls on each created pojo object.
+ * @param instance the created object (could be <code>null</code>)
+ */
+ public synchronized void invoke(Object instance) {
+ if (m_invoked) {
+ return; // Already called.
+ }
+
+ if (m_value == NO_VALUE) {
+ // Don't call method if no value
+ return;
+ }
+
+ try {
+ if (instance == null) {
+ m_method.call(new Object[] { m_value });
+ } else {
+ m_method.call(instance, new Object[] { m_value });
+ }
+ m_invoked = true;
+ } catch (NoSuchMethodException e) {
+ m_handler.error("The method " + m_method + " does not exist in the implementation class " + m_manager.getClassName(), e);
+ m_manager.stop();
+ } catch (IllegalAccessException e) {
+ m_handler.error("The method " + m_method + " is not accessible in the implementation class " + m_manager.getClassName(), e);
+ m_manager.stop();
+ } catch (InvocationTargetException e) {
+ m_handler.error("The method " + m_method + " in the implementation class " + m_manager.getClassName() + "throws an exception : " + e.getTargetException().getMessage(), e.getTargetException());
+ m_manager.setState(ComponentInstance.INVALID);
+ }
+ }
+
+ /**
+ * A field value is required by the object 'pojo'.
+ * @param pojo the POJO object
+ * @param fieldName the field
+ * @param value the last value
+ * @return the value if the handler want to inject this value.
+ * @see org.apache.felix.ipojo.FieldInterceptor#onGet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public synchronized Object onGet(Object pojo, String fieldName, Object value) {
+ if (m_value == NO_VALUE) {
+ return getNoValue(m_type);
+ }
+ return m_value;
+ }
+
+ /**
+ * The field 'field' receives a new value.
+ * @param pojo the pojo
+ * @param fieldName the field name
+ * @param value the new value
+ * @see org.apache.felix.ipojo.FieldInterceptor#onSet(java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public synchronized void onSet(Object pojo, String fieldName, Object value) {
+ if (m_value == null || ! m_value.equals(value)) {
+ setValue(value);
+ }
+ }
+
+ /**
+ * Gets the object to inject as constructor parameter.
+ * @param index the constructor parameter index
+ * @return the object to inject, so the property value.
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
+ */
+ public Object getConstructorParameter(int index) {
+ if (m_index != index) {
+ return null;
+ }
+
+ if (m_value == NO_VALUE) {
+ return getNoValue(m_type);
+ }
+ return m_value;
+ }
+
+ /**
+ * Gets the type of the constructor parameter to inject.
+ * @param index the parameter index
+ * @return the Class of the property.
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
+ */
+ public Class getConstructorParameterType(int index) {
+ if (m_index != index) {
+ return null;
+ }
+ return m_type;
+ }
+
+ /**
+ * Gets the handler managing the property.
+ * @return the configuration handler.
+ */
+ public Handler getHandler() {
+ return m_handler;
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Reflection.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Reflection.java
new file mode 100644
index 0000000..44201f3
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Reflection.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+/**
+ * Class containing utility method helping reflection
+ */
+public class Reflection {
+
+ public static <T> Fields<T> fields() {
+ return new Fields<T>();
+ }
+
+ public static <T> Methods<T> methods() {
+ return new Methods<T>();
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SecurityHelper.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SecurityHelper.java
new file mode 100644
index 0000000..32d4d36
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SecurityHelper.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.security.Permission;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServicePermission;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Methods checking security permissions.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SecurityHelper {
+
+
+ /**
+ * Gets a bundle context to register the given services.
+ * This method can be used only if iPOJO is able to
+ * registers the services (so for ManagedServiceFactory,
+ * Factory and Architecture)
+ * @param itfs the service interfaces
+ * @param comp the component bundle context
+ * @param ipojo the ipojo bundle context
+ * @return <code>comp</code> if the bundle has enough permission
+ * to register the service, <code>ipojo</code> otherwise.
+ */
+ public static BundleContext selectContextToRegisterServices(String[] itfs,
+ BundleContext comp, BundleContext ipojo) {
+ if (System.getSecurityManager() != null) {
+ for (String itf : itfs) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.REGISTER);
+ if (!comp.getBundle().hasPermission(perm)) {
+ return ipojo;
+ }
+ }
+
+ }
+ return comp;
+ }
+
+ /**
+ * Gets a bundle context to register the given service.
+ * This method can be used only if iPOJO is able to
+ * registers the service (so for ManagedServiceFactory,
+ * Factory and Architecture)
+ * @param itf the service interface
+ * @param comp the component bundle context
+ * @param ipojo the ipojo bundle context
+ * @return <code>comp</code> if the bundle has enough permission
+ * to register the service, <code>ipojo</code> otherwise.
+ */
+ public static BundleContext selectContextToRegisterService(String itf,
+ BundleContext comp, BundleContext ipojo) {
+ if (System.getSecurityManager() != null) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.REGISTER);
+ if (!comp.getBundle().hasPermission(perm)) {
+ return ipojo;
+ }
+ }
+ return comp;
+ }
+
+ /**
+ * Gets a bundle context to get the given service.
+ * This method can be used only if iPOJO is able to
+ * get the service (so for ManagedServiceFactory,
+ * Factory, Architecture and LogService)
+ * @param itf the service interface
+ * @param comp the component bundle context
+ * @param ipojo the ipojo bundle context
+ * @return <code>comp</code> if the bundle has enough permission
+ * to get the service, <code>ipojo</code> otherwise.
+ */
+ public static BundleContext selectContextToGetService(String itf,
+ BundleContext comp, BundleContext ipojo) {
+ if (System.getSecurityManager() != null) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.GET);
+ if (!comp.getBundle().hasPermission(perm)) {
+ return ipojo;
+ }
+ }
+ return comp;
+ }
+
+ /**
+ * Checks if the component bundle context has enough permission
+ * to get the given service.
+ * @param itf the service interface
+ * @param comp the component bundle context
+ * @return <code>true</code> if the bundle has enough permission
+ * to get the service, <code>false</code> otherwise.
+ */
+ public static boolean hasPermissionToGetService(String itf,
+ BundleContext comp) {
+ if (System.getSecurityManager() != null) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.GET);
+ return comp.getBundle().hasPermission(perm);
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the component bundle context has enough permission
+ * to get the given services.
+ * @param itfs the service interfaces
+ * @param comp the component bundle context
+ * @return <code>true</code> if the bundle has enough permission
+ * to get the services, <code>false</code> otherwise.
+ */
+ public static boolean hasPermissionToGetServices(String[] itfs,
+ BundleContext comp) {
+ if (System.getSecurityManager() != null) {
+ for (String itf : itfs) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.GET);
+ if (!comp.getBundle().hasPermission(perm)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the component bundle context has enough permission
+ * to register the given service.
+ * @param itf the service interface
+ * @param comp the component bundle context
+ * @return <code>true</code> if the bundle has enough permission
+ * to register the service, <code>false</code> otherwise.
+ */
+ public static boolean hasPermissionToRegisterService(String itf,
+ BundleContext comp) {
+ if (System.getSecurityManager() != null) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.REGISTER);
+ return comp.getBundle().hasPermission(perm);
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the component bundle context has enough permission
+ * to register the given services.
+ * @param itfs the service interfaces
+ * @param comp the component bundle context
+ * @return <code>true</code> if the bundle has enough permission
+ * to register the services, <code>false</code> otherwise.
+ */
+ public static boolean hasPermissionToRegisterServices(String[] itfs,
+ BundleContext comp) {
+ if (System.getSecurityManager() != null) {
+ for (String itf : itfs) {
+ final Permission perm = new ServicePermission(itf,
+ ServicePermission.REGISTER);
+ if (!comp.getBundle().hasPermission(perm)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks that the given bundle context is in a state where it is possible to register services.
+ * This methods ensures that the bundle associated to the given context, is starting or active.
+ * @param context the bundle context
+ * @return {@literal true} if the context can register a service, {@literal false} otherwise.
+ */
+ public static boolean canRegisterService(BundleContext context) {
+ return context.getBundle().getState() == Bundle.ACTIVE
+ || context.getBundle().getState() == Bundle.STARTING;
+ }
+
+ /**
+ * Checks that the given service registration can be updated.
+ * This methods ensures that the bundle associated to the given service, is starting or active.
+ * @param registration the service registration
+ * @return {@literal true} if the service can be updated, {@literal false} otherwise.
+ */
+ public static boolean canUpdateService(ServiceRegistration registration) {
+ if (registration == null) {
+ return false;
+ }
+ try {
+ BundleContext context = registration.getReference().getBundle().getBundleContext();
+ return context.getBundle().getState() == Bundle.ACTIVE
+ || context.getBundle().getState() == Bundle.STARTING;
+ } catch (IllegalStateException e) {
+ return false;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceLocator.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceLocator.java
new file mode 100644
index 0000000..98bc4fb
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceLocator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A simple utility class to retrive services from the service registry.
+ */
+public class ServiceLocator<T> {
+
+ private final BundleContext m_context;
+ private final Class<T> m_clazz;
+
+ private ServiceReference m_reference;
+ private T m_service;
+
+ public ServiceLocator(Class<T> clazz, BundleContext context) {
+ m_clazz = clazz;
+ m_context = context;
+ }
+
+ public synchronized T get() {
+ if (m_service != null) {
+ return m_service;
+ }
+
+ // We can't use the generic version, as KF does not support it yet.
+ m_reference = m_context.getServiceReference(m_clazz.getName());
+ if (m_reference == null) {
+ return null;
+ }
+
+ m_service = (T) m_context.getService(m_reference);
+
+ return m_service;
+ }
+
+ public synchronized void unget() {
+ m_service = null;
+ if (m_reference != null) {
+ m_context.ungetService(m_reference);
+ m_reference = null;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceReferenceRankingComparator.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceReferenceRankingComparator.java
new file mode 100644
index 0000000..112199c
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/ServiceReferenceRankingComparator.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service Reference Comparator.
+ * This comparator follows OSGi Ranking policy.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceReferenceRankingComparator implements Comparator<ServiceReference>, Serializable {
+
+ /**
+ * Id.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Compares two service reference.
+ * @param ref1 the reference 1
+ * @param ref2 the reference 2
+ * @return <code>-1</code> if the reference 1
+ * is 'higher' than the reference 2, <code>1</code> otherwise.
+ * (higher is term of ranking means a lower index)
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(ServiceReference ref1, ServiceReference ref2) {
+ if (ref1.equals(ref2)) { return 0; }
+
+ if (ref2 != null) {
+ Object property1 = ref1.getProperty(Constants.SERVICE_RANKING);
+ Object property2 = ref2.getProperty(Constants.SERVICE_RANKING);
+
+ int rank1 = 0;
+ int rank2 = 0;
+ if (property1 instanceof Integer) {
+ rank1 = (Integer) property1;
+ }
+ if (property2 instanceof Integer) {
+ rank2 = (Integer) property2;
+ }
+
+ if (rank1 == rank2) {
+ // Check service.id
+ Object sid1 = ref1.getProperty(Constants.SERVICE_ID);
+ Object sid2 = ref2.getProperty(Constants.SERVICE_ID);
+
+ long rankId1 = (Long) sid1;
+ long rankId2 = (Long) sid2;
+
+ if (rankId1 == rankId2) {
+ return 0;
+ } else if (rankId1 < rankId2) {
+ return -1;
+ } else {
+ return 1;
+ }
+
+ } else if (rank1 > rank2) {
+ return -1;
+ } else {
+ return 1;
+ }
+
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/StreamUtils.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/StreamUtils.java
new file mode 100644
index 0000000..9a91662
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/StreamUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Utility method to handle streams.
+ */
+public class StreamUtils {
+
+ /**
+ * Closes a stream.
+ * It ignores the IOException that may occur while closing the stream.
+ * @param stream the stream to close.
+ */
+ public static void closeQuietly(Closeable stream) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // Ignore.
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SystemPropertiesSource.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SystemPropertiesSource.java
new file mode 100644
index 0000000..69f93c8
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/SystemPropertiesSource.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+
+import java.util.Dictionary;
+
+/**
+ * A context source giving access to system properties.
+ */
+public class SystemPropertiesSource implements ContextSource {
+
+ public Object getProperty(String property) {
+ return System.getProperty(property);
+ }
+
+ public Dictionary getContext() {
+ return System.getProperties();
+ }
+
+ public void registerContextListener(ContextListener listener, String[] properties) {
+ // Ignored, as this source is not dynamic, so won't send notifications
+ }
+
+ public void unregisterContextListener(ContextListener listener) {
+ // Ignored, as this source is not dynamic, so won't send notifications
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java
new file mode 100644
index 0000000..f25cd67
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java
@@ -0,0 +1,753 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.ipojo.context.ServiceReferenceImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Utility class close to the OSGi Service Tracker.
+ * This class is used when tracking dynamic services is required.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Tracker implements TrackerCustomizer {
+
+ /**
+ * The bundle context against which this Tracker object is tracking.
+ */
+ protected BundleContext m_context;
+
+ /**
+ * the filter specifying search criteria for the services to track.
+ */
+ protected Filter m_filter;
+
+ /**
+ * The TrackerCustomizer object for this tracker.
+ */
+ protected TrackerCustomizer m_customizer;
+
+ /**
+ * The filter string for use when adding the ServiceListener.
+ * If this field is set, then certain optimizations can be taken since we don't have a user supplied filter.
+ */
+ protected String m_listenerFilter;
+
+ /**
+ * The class name to be tracked. If this field is set, then we are
+ * tracking by class name.
+ */
+ private String m_trackClass;
+
+ /**
+ * The reference to be tracked. If this field is set, then we are
+ * tracking a single ServiceReference.
+ */
+ private ServiceReference m_trackReference;
+
+ /**
+ * The tracked services: ServiceReference object -> customized.
+ *Object and ServiceListener object
+ */
+ private Tracked m_tracked;
+
+ /**
+ * The cached ServiceReference for getServiceReference.
+ * This field is volatile since it is accessed by multiple threads.
+ */
+ private volatile ServiceReference m_cachedReference;
+
+ /**
+ * The cached service object for getService. This field is volatile
+ * since it is accessed by multiple threads.
+ */
+ private volatile Object m_cachedService;
+
+ /**
+ * Creates a Tracker object on the specified ServiceReference object.
+ * The service referenced by the specified ServiceReference object will be tracked by this Tracker.
+ * @param context The BundleContext object against which the tracking is done.
+ * @param reference The ServiceReference object for the service to be tracked.
+ * @param customizer The customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as
+ * the TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.
+ */
+ public Tracker(BundleContext context, ServiceReference reference, TrackerCustomizer customizer) {
+ m_context = context;
+ m_trackReference = reference;
+ m_trackClass = null;
+ if (customizer == null) {
+ m_customizer = this;
+ } else {
+ m_customizer = customizer;
+ }
+ m_listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ try {
+ this.m_filter = context.createFilter(m_listenerFilter);
+ } catch (InvalidSyntaxException e) { // we could only get this exception if the ServiceReference was invalid
+ throw new IllegalArgumentException("unexpected InvalidSyntaxException", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Creates a Tracker object on the specified class name.
+ * Services registered under the specified class name will be tracked by this Tracker object.
+ * @param context the BundleContext object against which the tracking is done.
+ * @param clazz the Class name of the services to be tracked.
+ * @param customizer the customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as
+ * the TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.
+ */
+ public Tracker(BundleContext context, String clazz, TrackerCustomizer customizer) {
+ // Security Check
+ if (! SecurityHelper.hasPermissionToGetService(clazz, context)) {
+ throw new SecurityException("The bundle " + context.getBundle().getBundleId()
+ + " does not have the permission to get the service " + clazz);
+ }
+
+ this.m_context = context;
+ this.m_trackReference = null;
+ this.m_trackClass = clazz;
+ if (customizer == null) {
+ m_customizer = this;
+ } else {
+ m_customizer = customizer;
+ }
+ this.m_listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz + ")";
+ try {
+ this.m_filter = context.createFilter(m_listenerFilter);
+ } catch (InvalidSyntaxException e) { // we could only get this exception
+ // if the clazz argument was
+ // malformed
+ throw new IllegalArgumentException("unexpected InvalidSyntaxException", e);
+ }
+ }
+
+ /**
+ * Creates a Tracker object on the specified Filter object.
+ * <p>
+ * Services which match the specified Filter object will be tracked by this Tracker object.
+ * @param context the BundleContext object against which the tracking is done.
+ * @param filter the Filter object to select the services to be tracked.
+ * @param customizer The customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as the
+ * TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.
+ */
+ public Tracker(BundleContext context, Filter filter, TrackerCustomizer customizer) {
+ this.m_context = context;
+ this.m_trackReference = null;
+ this.m_trackClass = null;
+ this.m_listenerFilter = null;
+ this.m_filter = filter;
+ if (customizer == null) {
+ m_customizer = this;
+ } else {
+ m_customizer = customizer;
+ }
+ if ((context == null) || (filter == null)) { // we throw a NPE here to be consistent with the other constructors
+ throw new NullPointerException(); // NOPMD by clement on 29/02/08 14:12
+ }
+ }
+
+ /**
+ * Opens this Tracker object and begin tracking services.
+ * <p>
+ * Services which match the search criteria specified when this Tracker object was created are now tracked by this Tracker object.
+ */
+ public synchronized void open() {
+ if (m_tracked != null) { return; }
+
+ m_tracked = new Tracked();
+ synchronized (m_tracked) {
+ try {
+ m_context.addServiceListener(m_tracked, m_listenerFilter);
+ ServiceReference[] references;
+ if (m_listenerFilter == null) { // user supplied filter
+ references = getInitialReferences(null, m_filter.toString());
+ } else { // constructor supplied filter
+ if (m_trackClass == null) {
+ references = new ServiceReference[] { m_trackReference };
+ } else {
+ references = getInitialReferences(m_trackClass, null);
+ }
+ }
+
+ m_tracked.setInitialServices(references); // set tracked with
+ // the initial
+ // references
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException("unexpected InvalidSyntaxException", e); //$NON-NLS-1$
+ }
+ }
+ /* Call tracked outside of synchronized region */
+ m_tracked.trackInitialServices(); // process the initial references
+ }
+
+ /**
+ * Returns the list of initial ServiceReference objects that will be tracked by this Tracker object.
+ * @param trackClass the class name with which the service was registered, or null for all services.
+ * @param filterString the filter criteria or null for all services.
+ * @return the list of initial ServiceReference objects.
+ * @throws InvalidSyntaxException if the filter uses an invalid syntax.
+ */
+ private ServiceReference[] getInitialReferences(String trackClass, String filterString) throws InvalidSyntaxException {
+ return m_context.getServiceReferences(trackClass, filterString);
+ }
+
+ /**
+ * Closes this Tracker object.
+ * <p>
+ * This method should be called when this Tracker object should end the tracking of services.
+ */
+ public synchronized void close() {
+ if (m_tracked == null) { return; }
+
+ m_tracked.close();
+ ServiceReference[] references = getServiceReferences();
+ Tracked outgoing = m_tracked;
+
+ try {
+ m_context.removeServiceListener(outgoing);
+ } catch (IllegalStateException e) { //NOPMD
+ /* In case the context was stopped. */
+ }
+ if (references != null) {
+ for (ServiceReference reference : references) {
+ outgoing.untrack(reference);
+ }
+ }
+ m_tracked = null;
+
+ }
+
+ /**
+ * Default implementation of the TrackerCustomizer.addingService method.
+ * <p>
+ * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation returns the result of calling getService,
+ * on the BundleContext object with which this Tracker object was created, passing the specified ServiceReference object.
+ * <p>
+ * This method can be overridden in a subclass to customize the service object to be tracked for the service being added. In that case, take care not to rely on the default implementation of removedService that will unget the service.
+ * @param reference the Reference to service being added to this Tracker object.
+ * @return The service object to be tracked for the service added to this Tracker object.
+ * @see TrackerCustomizer
+ */
+ public boolean addingService(ServiceReference reference) {
+ return true;
+ }
+
+ /**
+ * Default implementation of the TrackerCustomizer.addedService method.
+ * @param reference the added reference.
+ * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+ */
+ public void addedService(ServiceReference reference) {
+ // Nothing to do.
+ }
+
+ /**
+ * Default implementation of the TrackerCustomizer.modifiedService method.
+ * <p>
+ * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation does nothing.
+ * @param reference the Reference to modified service.
+ * @param service The service object for the modified service.
+ * @see TrackerCustomizer
+ */
+ public void modifiedService(ServiceReference reference, Object service) {
+ // Nothing to do.
+ }
+
+ /**
+ * Default implementation of the TrackerCustomizer.removedService method.
+ * <p>
+ * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation calls ungetService, on the
+ * BundleContext object with which this Tracker object was created, passing the specified ServiceReference object.
+ * <p>
+ * This method can be overridden in a subclass. If the default implementation of addingService method was used, this method must unget the service.
+ * @param reference the Reference to removed service.
+ * @param service The service object for the removed service.
+ * @see TrackerCustomizer
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ m_context.ungetService(reference);
+ }
+
+ /**
+ * Waits for at least one service to be tracked by this Tracker object.
+ * <p>
+ * It is strongly recommended that waitForService is not used during the calling of the BundleActivator methods. BundleActivator methods are expected to complete in a short period of time.
+ * @param timeout the time interval in milliseconds to wait. If zero, the method will wait indefinately.
+ * @return Returns the result of getService().
+ * @throws InterruptedException If another thread has interrupted the current thread.
+ */
+ public Object waitForService(long timeout) throws InterruptedException {
+ if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); }
+ Object object = getService();
+ while (object == null) {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return null;
+ }
+ synchronized (tracked) {
+ if (tracked.size() == 0) {
+ tracked.wait(timeout);
+ }
+ }
+ object = getService();
+ if (timeout > 0) { return object; }
+ }
+ return object;
+ }
+
+ /**
+ * Returns an array of ServiceReference objects for all services being tracked by this Tracker object.
+ * @return Array of ServiceReference objects or <code>null</code> if no service are being tracked.
+ */
+ public ServiceReference[] getServiceReferences() {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { // if Tracker is not open
+ return null;
+ }
+ synchronized (tracked) {
+ int length = tracked.size();
+ if (length == 0) { return null; }
+ ServiceReference[] references = new ServiceReference[length];
+ Iterator keys = tracked.keySet().iterator();
+ for (int i = 0; i < length; i++) {
+ references[i] = (ServiceReference) keys.next();
+ }
+ return references;
+ }
+ }
+
+ /**
+ * Gets the list of stored service references.
+ * @return the list containing service references
+ */
+ public List<ServiceReference> getServiceReferencesList() {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { // if Tracker is not open
+ return null;
+ }
+ synchronized (tracked) {
+ int length = tracked.size();
+ if (length == 0) { return null; }
+ List<ServiceReference> references = new ArrayList<ServiceReference>(length);
+ references.addAll(tracked.keySet());
+ // The resulting array is sorted by ranking.
+ return references;
+ }
+ }
+
+ /**
+ * Returns the list of references used by the tracker.
+ * A reference becomes used when the dependency has already
+ * called getService on this reference.
+ * @return the list of used references.
+ */
+ public List<ServiceReference> getUsedServiceReferences() {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null || tracked.size() == 0) { // if Tracker is not open or empty
+ return null;
+ }
+ synchronized (tracked) {
+ List<ServiceReference> references = new ArrayList<ServiceReference>();
+ for (Map.Entry<ServiceReference, Object> entry : tracked.entrySet()) {
+ if (entry.getValue() != null) {
+ references.add(entry.getKey());
+ }
+ }
+ return references;
+ }
+ }
+
+ /**
+ * Returns a ServiceReference object for one of the services being tracked by this Tracker object.
+ * If multiple services are being tracked, the service with the highest ranking (as specified in its service.ranking property) is returned.
+ * If there is a tie in ranking, the service with the lowest service ID (as specified in its service.id property); that is, the service that was registered first is returned.
+ * This is the same algorithm used by BundleContext.getServiceReference.
+ * @return ServiceReference object or null if no service is being tracked.
+ * @since 1.1
+ */
+ public ServiceReference getServiceReference() {
+ ServiceReference reference = m_cachedReference;
+ if (reference != null) { return reference; }
+
+ ServiceReference[] references = getServiceReferences();
+ if (references == null) {
+ return null;
+ } else {
+ // As the map is sorted, return the first element.
+ return m_cachedReference = references[0];
+ }
+ }
+
+ /**
+ * Returns the service object for the specified ServiceReference object if the referenced service is being tracked by this Tracker object.
+ * @param reference the Reference to the desired service.
+ * @return the Service object. Try to get the service if not yet tracked.
+ */
+ public Object getService(ServiceReference reference) {
+ // Security Check
+ if (! SecurityHelper.hasPermissionToGetServices((String[]) reference.getProperty(Constants.OBJECTCLASS),
+ m_context)) {
+ throw new SecurityException("The bundle " + m_context.getBundle().getBundleId() + " does not have"
+ + " the permission to get the services "
+ + Arrays.asList((String[]) reference.getProperty(Constants.OBJECTCLASS)));
+ }
+
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return null;
+ }
+ synchronized (tracked) {
+ Object object = tracked.get(reference);
+ if (object == null) {
+ if (tracked.containsKey(reference)) { // Not already get but already tracked.
+ object = m_context.getService(reference);
+ tracked.put(reference, object);
+ return object;
+ }
+ } else { // The object was already retrieved.
+ return object;
+ }
+
+ return m_context.getService(reference);
+ }
+ }
+
+ /**
+ * Ungets the given service reference.
+ * @param reference the service reference to unget.
+ */
+ public void ungetService(ServiceReference reference) {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return;
+ }
+ Object object = null;
+ synchronized (tracked) {
+ object = tracked.get(reference);
+ }
+ if (object != null) {
+ m_context.ungetService(reference);
+ }
+ }
+
+ /**
+ * Returns an array of service objects for all services being tracked by this Tracker object.
+ * @return Array of service objects or <code>null</code> if no service are being tracked.
+ */
+ public Object[] getServices() {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return null;
+ }
+ synchronized (tracked) {
+ ServiceReference[] references = getServiceReferences();
+ int length;
+ if (references == null) {
+ return null;
+ } else {
+ length = references.length;
+ }
+ Object[] objects = new Object[length];
+ for (int i = 0; i < length; i++) {
+ objects[i] = getService(references[i]);
+ }
+ return objects;
+ }
+ }
+
+ /**
+ * Returns a service object for one of the services being tracked by this Tracker object.
+ * <p>
+ * If any services are being tracked, this method returns the result of calling getService(getServiceReference()).
+ * @return Service object or <code>null</code> if no service is being tracked.
+ */
+ public Object getService() {
+ Object service = m_cachedService;
+ if (service != null) { return service; }
+ ServiceReference reference = getServiceReference();
+ if (reference == null) { return null; }
+ return m_cachedService = getService(reference);
+ }
+
+ /**
+ * Removes a service from this Tracker object. The specified service will be removed from this Tracker object. If the specified service was being tracked then the
+ * TrackerCustomizer.removedService method will be called for that service.
+ * @param reference the Reference to the service to be removed.
+ */
+ public void remove(ServiceReference reference) {
+ Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return;
+ }
+ tracked.untrack(reference);
+ }
+
+ /**
+ * Returns the number of services being tracked by this Tracker object.
+ * @return the Number of services being tracked.
+ */
+ public int size() {
+ Tracked tracked = this.m_tracked; //use local var since we are not synchronized
+ if (tracked == null) { /* if Tracker is not open */
+ return 0;
+ }
+ return tracked.size();
+ }
+
+ /**
+ * Inner class to track services. If a Tracker object is reused (closed then reopened), then a new Tracked object is used. This class is a hashtable mapping ServiceReference object -> customized Object. This
+ * class is the ServiceListener object for the tracker. This class is used to synchronize access to the tracked services. This is not a public class. It is only for use by the implementation of the Tracker
+ * class.
+ */
+ class Tracked extends HashMap<ServiceReference, Object> implements ServiceListener {
+
+ /**
+ * The list of ServiceReferences in the process of being added. This is used to deal with nesting of ServiceEvents. Since ServiceEvents are synchronously delivered, ServiceEvents can be nested. For example, when processing the adding of a service
+ * and the customizer causes the service to be unregistered, notification to the nested call to untrack that the service was unregistered can be made to the track method. Since the ArrayList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for thread safety.
+ */
+ private List<ServiceReference> m_adding;
+
+ /**
+ * <code>true</code> if the tracked object is closed. This field is volatile because it is set by one thread and read by another.
+ */
+ private volatile boolean m_closed;
+
+ /**
+ * The Initial list of ServiceReferences for the tracker. This is used to correctly process the initial services which could become unregistered before they are tracked. This is necessary since the initial set of tracked services are not
+ * "announced" by ServiceEvents and therefore the ServiceEvent for unregistration could be delivered before we track the service. A service must not be in both the initial and adding lists at the same time. A service must be moved from the
+ * initial list to the adding list "atomically" before we begin tracking it. Since the LinkedList implementation is not synchronized, all access to this list must be protected by the same synchronized object for thread safety.
+ */
+ private List<ServiceReference> m_initial;
+
+ /**
+ * Tracked constructor.
+ */
+ protected Tracked() {
+ super();
+ m_closed = false;
+ m_adding = new ArrayList<ServiceReference>(6);
+ m_initial = new LinkedList<ServiceReference>();
+ }
+
+ /**
+ * Sets initial list of services into tracker before ServiceEvents begin to be received. This method must be called from Tracker.open while synchronized on this object in the same synchronized block as the addServiceListener call.
+ * @param references The initial list of services to be tracked.
+ */
+ protected void setInitialServices(ServiceReference[] references) {
+ if (references == null) { return; }
+ int size = references.length;
+ m_initial.addAll(Arrays.asList(references).subList(0, size));
+ }
+
+ /**
+ * Tracks the initial list of services. This is called after ServiceEvents can begin to be received. This method must be called from Tracker.open while not synchronized on this object after the addServiceListener call.
+ */
+ protected void trackInitialServices() {
+ while (true) {
+ ServiceReference reference;
+ synchronized (this) {
+ if (m_initial.isEmpty()) { // if there are no more initial services
+ return; // we are done
+ }
+
+ // move the first service from the initial list to the adding list within this synchronized block.
+ reference = (ServiceReference) ((LinkedList) m_initial).removeFirst();
+ if (this.containsKey(reference)) { //Check if the reference is already tracked.
+ //if we are already tracking this service
+ continue; /* skip this service */
+ }
+ if (m_adding.contains(reference)) {
+ // if this service is already in the process of being added.
+ continue; // skip this service
+ }
+ m_adding.add(reference);
+ }
+ trackAdding(reference); // Begin tracking it. We call trackAdding since we have already put the reference in the adding list.
+ }
+ }
+
+ /**
+ * Called by the owning Tracker object when it is closed.
+ */
+ protected void close() {
+ m_closed = true;
+ }
+
+ /**
+ * ServiceListener method for the Tracker class. This method must NOT be synchronized to avoid deadlock potential.
+ * @param event the ServiceEvent object from the framework.
+ */
+ public void serviceChanged(ServiceEvent event) {
+ //Check if we had a delayed call (which could happen when we close).
+ if (m_closed) { return; }
+ ServiceReference reference = event.getServiceReference();
+
+ switch (event.getType()) {
+ case ServiceEvent.REGISTERED:
+ case ServiceEvent.MODIFIED:
+ if (m_listenerFilter == null) { // user supplied filter
+ boolean match = true;
+ if (reference instanceof ServiceReferenceImpl) {
+ // Can't use the match(ref) as it throw a class cast exception on Equinox.
+ match = m_filter.match(((ServiceReferenceImpl) reference).getProperties());
+ } else { // Non computed reference.
+ match = m_filter.match(reference);
+ }
+ if (match) {
+ track(reference); // Arrival
+ } else {
+ untrack(reference); // Departure
+ }
+ } else { // constructor supplied filter
+ track(reference);
+ }
+ break;
+ case ServiceEvent.UNREGISTERING:
+ untrack(reference); // Departure
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Begins to track the referenced service.
+ * @param reference the Reference to a service to be tracked.
+ */
+ protected void track(ServiceReference reference) {
+ Object object;
+ boolean alreadyTracked;
+ synchronized (this) {
+ alreadyTracked = this.containsKey(reference);
+ object = this.get(reference);
+ }
+ if (alreadyTracked) { // we are already tracking the service
+ if (object != null) { // If already get, invalidate the cache
+ synchronized (this) {
+ modified();
+ }
+ }
+ // Call customizer outside of synchronized region
+ m_customizer.modifiedService(reference, object);
+ return;
+ }
+ synchronized (this) {
+ if (m_adding.contains(reference)) { // if this service is already in the process of being added.
+ return;
+ }
+ m_adding.add(reference); // mark this service is being added
+ }
+
+ trackAdding(reference); // call trackAdding now that we have put the reference in the adding list
+ }
+
+ /**
+ * Common logic to add a service to the tracker used by track and trackInitialServices.
+ * The specified reference must have been placed in the adding list before calling this method.
+ * @param reference the Reference to a service to be tracked.
+ */
+ private void trackAdding(ServiceReference reference) {
+ boolean mustBeTracked = false;
+ boolean becameUntracked = false;
+ boolean mustCallAdded = false;
+ //Call customizer outside of synchronized region
+ try {
+ mustBeTracked = m_customizer.addingService(reference);
+ } finally {
+ synchronized (this) {
+ if (m_adding.remove(reference)) { // if the service was not untracked during the customizer callback
+ if (mustBeTracked) {
+ this.put(reference, null);
+ modified();
+ mustCallAdded = true;
+ notifyAll(); // notify any waiters in waitForService
+ }
+ } else {
+ becameUntracked = true;
+ // If already get during the customizer callback
+ ungetService(reference);
+ modified();
+ }
+ }
+ }
+
+ // Call customizer outside of synchronized region
+ if (becameUntracked) {
+ // The service became untracked during the customizer callback.
+ m_customizer.removedService(reference, null);
+ } else {
+ if (mustCallAdded) {
+ m_customizer.addedService(reference);
+ }
+ }
+ }
+
+ /**
+ * Discontinues tracking the referenced service.
+ * @param reference the Reference to the tracked service.
+ */
+ protected void untrack(ServiceReference reference) {
+ Object object;
+ synchronized (this) {
+ if (m_initial.remove(reference)) { // if this service is already in the list of initial references to process
+ return; // we have removed it from the list and it will not be processed
+ }
+
+ if (m_adding.remove(reference)) { // if the service is in the process of being added
+ return; // in case the service is untracked while in the process of adding
+ }
+
+ boolean isTraked = this.containsKey(reference); // Check if we was tracking the reference
+ object = this.remove(reference); // must remove from tracker before calling customizer callback
+
+ if (!isTraked) { return; }
+ modified();
+ }
+ // Call customizer outside of synchronized region and only if we are not closed
+ if (! m_closed) {
+ m_customizer.removedService(reference, object);
+ }
+ // If the customizer throws an unchecked exception, it is safe to let it propagate
+ }
+
+ /**
+ * Called by the Tracked object whenever the set of tracked services is modified. Increments the tracking count and clears the cache.
+ * This method must not be synchronized since it is called by Tracked while Tracked is synchronized. We don't want synchronization interactions between the ServiceListener thread and the user thread.
+ */
+ void modified() {
+ m_cachedReference = null; /* clear cached value */
+ m_cachedService = null; /* clear cached value */
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/TrackerCustomizer.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/TrackerCustomizer.java
new file mode 100644
index 0000000..81bd73b
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/TrackerCustomizer.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Tracker Customizer.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface TrackerCustomizer {
+
+ /**
+ * A service is being added to the Tracker object.
+ * This method is called before a service which matched the search parameters of the Tracker object is added to
+ * it. This method should return the service object to be tracked for this ServiceReference object.
+ * If this method returns {@code true}, the service object becomes available from the {@link Tracker#getService()} and
+ * {@link Tracker#getServices()} methods. However notice that the service is still not accessible at that time.
+ * @param reference the Reference to service being added to the Tracker object.
+ * @return {@code true} if the service reference must be tracked. {@code false} ff the service reference must be
+ * ignored (un-tracked)
+ */
+ boolean addingService(ServiceReference reference);
+
+ /**
+ * A service tracked by the Tracker object has been added in the list.
+ * This method is called when a service has been added in the managed list (after addingService) and if the
+ * service has not disappeared before during the callback.
+ * In this method, the service object is accessible from the {@link Tracker#getService()} and
+ * {@link Tracker#getServices()} method.
+ * @param reference the added reference.
+ */
+ void addedService(ServiceReference reference);
+
+ /**
+ * A service tracked by the Tracker object has been modified.
+ * This method is called when a service tracked by the Tracker has its properties modified.
+ * @param reference the reference to service that has been modified.
+ * @param service The service object for the modified service.
+ */
+ void modifiedService(ServiceReference reference, Object service);
+
+ /**
+ * A service tracked by the Tracker object has been removed.
+ * This method is called when a tracked service is no longer being tracked by the Tracker object.
+ * Notice that some OSGi implementations does not support getting the service object from the bundle context in
+ * this method. The cached (given) object must be used.
+ * @param reference the reference to service that has been removed.
+ * @param service The service object for the removed service.
+ */
+ void removedService(ServiceReference reference, Object service);
+
+}
diff --git a/ipojo/runtime/core/src/main/resources/core.xsd b/ipojo/runtime/core/src/main/resources/core.xsd
new file mode 100644
index 0000000..3c729c9
--- /dev/null
+++ b/ipojo/runtime/core/src/main/resources/core.xsd
@@ -0,0 +1,704 @@
+<!--
+ ~ 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.
+ -->
+<xs:schema elementFormDefault="qualified" targetNamespace="org.apache.felix.ipojo"
+ xmlns="org.apache.felix.ipojo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:annotation>
+ <xs:documentation>iPOJO Core XML-Schema. This grammars models iPOJO descriptor using core
+ features. It provides several extensibility mechanism in order to compose this schema with
+ external handlers and other component implementation type such as
+ compositions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:element name="ipojo">
+ <xs:complexType>
+ <xs:annotation>
+ <xs:documentation>iPOJO top level element.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="handler" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The handler declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="instance" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The instance declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="component" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The component type declarations.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="HandlerType">
+ <xs:annotation>
+ <xs:documentation>Description of the handler.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence maxOccurs="unbounded" minOccurs="0">
+ <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="skip"
+ ></xs:any>
+ </xs:sequence>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The implementation class of the handler. The specified class must
+ implement (direcly or not) the "org.apache.felix.ipojo.Handler"
+ interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="namespace" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The XML namespace of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional" fixed="false">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is not exposed. This allows handler introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="level" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>The start level of the handler.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstanceType">
+ <xs:annotation>
+ <xs:documentation>Describes an instance of a component.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="RootElementType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>The instance props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="component" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>The name of the instance component type.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The (unique) name of the instance.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The version of the factory to use.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="InstancePropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a property of an instance configuration.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="property" type="InstancePropertyType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property. Can be optional if a property is inside a structure.
+ The 'instance.name' property has a special semantic as it will be used as the instance
+ name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Value of the property. Can be null for property containing other
+ props.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property, used to create the adequate object. Supported values
+ are list, array, dictionary and map.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RootElementType"/>
+ <xs:complexType name="ComponentType">
+ <xs:annotation>
+ <xs:documentation>Declares an atomic (i.e. primitive) component type.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="callback" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the method(s) to invoke when the component's state
+ changes.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the component provided service(s). By default, all implemented
+ interfaces are published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Indicates the service requirements of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="properties" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>Describes the properties of the component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="controller" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>Lifecycle controller for this component.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+ ></xs:any>
+ </xs:choice>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the name of the component type. This name is used to identify
+ the factory attached to this type. If not specified, the factory name is the
+ implementation class name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="public" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Determines if the component type is public or private. A public factory
+ (default) can be used from any bundles.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="classname" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the implementation class of the component
+ type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="architecture" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or disables the architecture exposition. By default, the
+ architecture is exposed. This allows instance introspection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immediate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Creates the object of the component implementation type as soon as the
+ component instance becomes valid. The default value is "true" if the component doesn't
+ provide any service, "false" otherwise.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory-method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Factory method called to create POJO objects instead of the constructor.
+ The specified method must be a static method of the implementation class returning an
+ instance of this implementation class. The factory method can receive the bundle context
+ in argument.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Set the version of this component type</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="RequiresType">
+ <xs:annotation>
+ <xs:documentation>Description of component services requirements.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="ServiceDependencyType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="callback" type="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Service requirement method invocation description. Here can be
+ specified a bind method called when a service appears and an unbind method called
+ when a service disappears.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>The interface describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type
+ of this field is a list, vector, collection and set. This attribute is deprecated, use
+ 'specification'.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The name of the field representing the service dependency in the
+ implementation class.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="nullable" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enable or disable the Nullable pattern on optional service
+ dependencies. By default, Nullable pattern is enabled. If disabled, iPOJO will inject
+ null instead of a Nullable object.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="default-implementation" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the default implementation class for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ default-implementation (nullary constructor) and injects it. The given class must
+ implement the required service interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </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 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="from" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specific service provider. The dependency can only be fulfilled by the
+ component with the matching name, or by the service with a matching
+ PID.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="proxy" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Enables or Disable the proxy injection (on field
+ injection)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="scope" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="global"/>
+ <xs:enumeration value="composite"/>
+ <xs:enumeration value="composite+global"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="DependencyCallbackType">
+ <xs:annotation>
+ <xs:documentation>Dependency callbacks are used to receive notification when service providers
+ arrive and leave.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Method to call</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" use="required">
+ <xs:annotation>
+ <xs:documentation>Type of callback (bind, unbind, or updated). Bind means that the method
+ will be called when a provider arrives. Unbind means that the method will be called when a
+ provider leaves. Updated means that a service was modified but is still valid for the
+ service dependency.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="bind"/>
+ <xs:enumeration value="unbind"/>
+ <xs:enumeration value="modified"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="CallbackType">
+ <xs:annotation>
+ <xs:documentation>Lifecycle Callback. Allows a POJO to be notified when the instance becomes
+ valid or invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the method to call on the transition.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="transition" use="required">
+ <xs:annotation>
+ <xs:documentation>Specifies the transition when the callback needs to be
+ invoked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>Lifecycle transition state. "validate" means that the component's
+ instance was invalid and becomes valid, "invalidate" means that the component's intance
+ was valid and becomes invalid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="validate"/>
+ <xs:enumeration value="invalidate"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ContextType">
+ <xs:annotation>
+ <xs:documentation>Allows injecting the OSGi bundle context into the component.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the method receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the field receiving the bundle context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="constructor-parameter" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the index of the parameter (0-based) receiving the bundle
+ context.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="context" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the context source.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:annotation>
+ <xs:documentation>iPOJO supports two bundle context 'sources': component and instance. Component
+ is the bundle context of the bundle declaring the component, while instance is the bundle
+ context of the bundle declaring the instance. Obviously, they are the same when the instance
+ is declared in the same bundle as the component. By default, it uses 'component'.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="instance"/>
+ <xs:enumeration value="component"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="provides" type="ProvidesType" id="provides"/>
+ <xs:complexType name="ProvidesType">
+ <xs:annotation>
+ <xs:documentation>Provided service(s) description.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>List of service specific props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="controller" minOccurs="0" maxOccurs="1" type="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Service Controller impacting the current provided
+ service
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="interface" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Deprecated attribute, use 'specifications' instead of
+ 'interface'
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specifications" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The list of service specifications (i.e. interfaces) to expose. By
+ default, all interfaces implemented by the component implementation class are
+ published.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="factory" type="xs:string" use="prohibited">
+ <xs:annotation>
+ <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="strategy" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>POJO creation strategy. By default, the POJO object is created once
+ (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi
+ service factory policy (one object object per asking bundle). INSTANCE allows creating one
+ different POJO object per asking instance. Finally, a custom strategy can be used by
+ specifying the qualified name of the class extending CreationPolicy
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-registration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service registration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="post-unregistration" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Defines a callback called after the service unregistration. The callback takes a
+ ServiceReference
+ as parameter
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="ServiceControllerType">
+ <xs:annotation>
+ <xs:documentation>Defines a service controller.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Field of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Intiail value of the controller</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:complexType name="PropertyType">
+ <xs:annotation>
+ <xs:documentation>Defines a component property.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Field of the property</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="method" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Setter method of the property. This method is called to inject property
+ value.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Name of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Default value of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Type of the property.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="mandatory" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as mandatory. A mandatory property MUST receive a value
+ either in the component type description or in the instance configuration. Properties are
+ optional by default.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="immutable" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>Set the property as immutable. An immutable property is inherited by the component
+ instance but the value cannot be overridden.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ <xs:element name="callback" type="CallbackType" id="callback"/>
+ <xs:element name="context" type="ContextType" id="context"/>
+ <xs:element name="controller" type="ControllerType" id="controller">
+ <xs:annotation>
+ <xs:documentation/>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="requires" type="RequiresType" id="requires"/>
+ <xs:element name="component" type="ComponentType" id="component"/>
+ <xs:element name="handler" type="HandlerType" id="handler"/>
+ <xs:element name="instance" type="InstanceType" id="instance"/>
+
+ <xs:element name="properties" type="PropertiesType" id="properties"/>
+ <xs:complexType name="PropertiesType">
+ <xs:annotation>
+ <xs:documentation>List of component, instance or service props. This field will receive
+ the property value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="property" type="PropertyType">
+ <xs:annotation>
+ <xs:documentation>The list of props.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="propagation" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Propagation of the component properties to the provided services. If this
+ parameter is set to "true", each time properties are reconfigured, they are propagated to
+ each service published by the component.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="pid" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Unique identifier used to reconfigure components properties (via Managed
+ Services) with the Configuration Admin.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="updated" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Method called when a reconfiguration is done</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ServiceDependencyType">
+ <xs:attribute name="specification" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The specification describing the required service type. This attribute is
+ needed only when using aggregate dependencies with field injection and when the type of
+ this field is a list, vector, collection and set.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="optional" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency optionality</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="aggregate" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the service dependency cardinality.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="policy" use="optional">
+ <xs:annotation>
+ <xs:documentation>Sets the binding policy of the dependency. Three policies are supported.
+ The dynamic policy supports service providers dynamism. The static policy freezes the
+ provider set as soon as the dependency is used. The dynamic-priority policy is an
+ extension of the dynamic policy, but providers are ranked.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="dynamic"/>
+ <xs:enumeration value="static"/>
+ <xs:enumeration value="dynamic-priority"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="comparator" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The comparator attribute allows specifying the class used to compare
+ providers. This class must implemented the java.util.Comparator class and must support the
+ comparison of service references.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="filter" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>LDAP filter used to filter providers</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>id of the service dependency. The id allows to identify and to refer to
+ this dependency.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="ControllerType">
+ <xs:annotation>
+ <xs:documentation>Specifies the lifecycle controller of a component, which allows to validate
+ or invalidate component instances.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The name of the component lifecycle controller field. The type of the
+ specified field must be boolean. Setting the value of the specified field to "true" means
+ the validation of the component instance while setting it to "false" means the
+ invalidation of the component instance.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
diff --git a/ipojo/runtime/core/src/main/resources/metadata.xml b/ipojo/runtime/core/src/main/resources/metadata.xml
new file mode 100644
index 0000000..b1b4e9e
--- /dev/null
+++ b/ipojo/runtime/core/src/main/resources/metadata.xml
@@ -0,0 +1,49 @@
+<!--
+ 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.
+-->
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <!-- Primitives handler -->
+ <handler
+ classname="org.apache.felix.ipojo.handlers.lifecycle.controller.ControllerHandler"
+ name="controller" architecture="false"/>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.lifecycle.callback.LifecycleCallbackHandler"
+ name="callback" level="2" architecture="false"/>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.context.BundleContextHandler"
+ name="context" level="0" architecture="false">
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.dependency.DependencyHandler"
+ name="requires" level="0" architecture="false">
+ <!-- <controller field="m_state"/> -->
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler"
+ name="provides" level="3" architecture="false"/>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.configuration.ConfigurationHandler"
+ name="properties" level="1" architecture="false"/>
+ <handler
+ classname="org.apache.felix.ipojo.handlers.architecture.ArchitectureHandler"
+ name="architecture" architecture="false">
+ <!-- The architecture service is published by the handler manually -->
+ </handler>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/IPojoFactoryTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/IPojoFactoryTestCase.java
new file mode 100644
index 0000000..434879f
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/IPojoFactoryTestCase.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 03/10/13
+ * Time: 11:53
+ */
+public class IPojoFactoryTestCase extends TestCase {
+ @Mock
+ private IPojoFactory.NameGenerator m_delegate;
+ @Mock
+ private Factory m_factory;
+ @Mock
+ private BundleContext m_bundleContext;
+ @Mock
+ private Bundle m_bundle;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testRetryNameGenerator() throws Exception {
+ when(m_factory.getName()).thenReturn("test");
+ when(m_delegate.generate(eq(m_factory), anyList())).thenReturn("my.instance");
+
+ IPojoFactory.RetryNameGenerator retry = new IPojoFactory.RetryNameGenerator(m_delegate);
+
+ assertEquals("my.instance", retry.generate(m_factory, Collections.<String>emptyList()));
+ }
+
+ public void testRetryNameGeneratorWithCollisions() throws Exception {
+ when(m_factory.getName()).thenReturn("test");
+ when(m_delegate.generate(eq(m_factory), anyList())).thenReturn("my.instance", "my.instance2");
+
+ IPojoFactory.RetryNameGenerator retry = new IPojoFactory.RetryNameGenerator(m_delegate);
+
+ assertEquals("my.instance2", retry.generate(m_factory, Arrays.asList("my.instance")));
+ }
+
+ public void testRetryNameGeneratorDoNotGenerateStackOverflow() throws Exception {
+ when(m_factory.getName()).thenReturn("test");
+ when(m_delegate.generate(eq(m_factory), anyList())).thenReturn("my.instance");
+ when(m_factory.getBundleContext()).thenReturn(m_bundleContext);
+ when(m_bundleContext.getBundle()).thenReturn(m_bundle);
+ when(m_bundle.getBundleId()).thenReturn(42l);
+
+ IPojoFactory.RetryNameGenerator retry = new IPojoFactory.RetryNameGenerator(m_delegate);
+ retry.setMaximum(100);
+
+ try {
+ retry.generate(m_factory, Arrays.asList("my.instance"));
+ } catch (UnacceptableConfiguration unacceptableConfiguration) {
+ return;
+ }
+ fail("Expecting an Exception");
+ }
+
+
+ public void testDefaultNameGenerator() throws Exception {
+ when(m_factory.getName()).thenReturn("test");
+
+ IPojoFactory.DefaultNameGenerator generator = new IPojoFactory.DefaultNameGenerator();
+
+ assertEquals("test-0", generator.generate(m_factory, null));
+ assertEquals("test-1", generator.generate(m_factory, null));
+ assertEquals("test-2", generator.generate(m_factory, null));
+ assertEquals("test-3", generator.generate(m_factory, null));
+ assertEquals("test-4", generator.generate(m_factory, null));
+ }
+
+ public void testDefaultNameGeneratorWithVersion() throws Exception {
+ when(m_factory.getName()).thenReturn("test");
+ when(m_factory.getVersion()).thenReturn("1.2.3");
+
+ IPojoFactory.DefaultNameGenerator generator = new IPojoFactory.DefaultNameGenerator();
+
+ assertEquals("test/1.2.3-0", generator.generate(m_factory, null));
+ assertEquals("test/1.2.3-1", generator.generate(m_factory, null));
+ assertEquals("test/1.2.3-2", generator.generate(m_factory, null));
+ assertEquals("test/1.2.3-3", generator.generate(m_factory, null));
+ assertEquals("test/1.2.3-4", generator.generate(m_factory, null));
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/InstanceManagerTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/InstanceManagerTest.java
new file mode 100644
index 0000000..1b195dd
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/InstanceManagerTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.lang.reflect.Member;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class InstanceManagerTest {
+
+ private static final int CALLERS = 500;
+
+ @Test
+ public void testConcurrencyOfMethodId() throws InterruptedException, ConfigurationException, ClassNotFoundException {
+ ExecutorService executor = Executors.newFixedThreadPool(CALLERS);
+ final AtomicInteger counter = new AtomicInteger();
+ final AtomicInteger error = new AtomicInteger();
+
+ ComponentFactory factory = mock(ComponentFactory.class);
+ when(factory.loadClass(anyString())).thenReturn(MyComponent.class);
+ when(factory.getClassName()).thenReturn(MyComponent.class.getName());
+ Bundle bundle = mock(Bundle.class);
+ when(bundle.getHeaders()).thenReturn(new Hashtable<String, String>());
+ BundleContext context = mock(BundleContext.class);
+ when(context.getBundle()).thenReturn(bundle);
+ InstanceManager manager = new InstanceManager(factory, context, new HandlerManager[0]);
+
+ Element method1 = new Element("method", "");
+ method1.addAttribute(new Attribute("name", "foo"));
+ method1.addAttribute(new Attribute("arguments", "{java.lang.String}"));
+ method1.addAttribute(new Attribute("names", "{name}"));
+
+ Element method2 = new Element("method", "");
+ method2.addAttribute(new Attribute("name", "bar"));
+ method2.addAttribute(new Attribute("arguments", "{java.lang.String}"));
+ method2.addAttribute(new Attribute("names", "{name}"));
+
+ Element method3 = new Element("method", "");
+ method3.addAttribute(new Attribute("name", "baz"));
+ method3.addAttribute(new Attribute("arguments", "{java.lang.String}"));
+ method3.addAttribute(new Attribute("names", "{name}"));
+ final MethodMetadata metadata1 = new MethodMetadata(method1);
+ final MethodInterceptor interceptor = new MethodInterceptor() {
+ public void onEntry(Object pojo, Member method, Object[] args) {
+ if (method != null) {
+ counter.getAndIncrement();
+ } else {
+ System.out.println("No method object for " + args[0]);
+ error.incrementAndGet();
+ }
+ }
+
+ public void onExit(Object pojo, Member method, Object returnedObj) {
+ if (method != null) {
+ counter.getAndDecrement();
+ } else {
+ System.out.println("No method object");
+ error.incrementAndGet();
+ }
+ }
+
+ public void onError(Object pojo, Member method, Throwable throwable) {
+
+ }
+
+ public void onFinally(Object pojo, Member method) {
+
+ }
+ };
+ manager.register(metadata1, interceptor);
+ final MethodMetadata metadata2 = new MethodMetadata(method2);
+ manager.register(metadata2, interceptor);
+ final MethodMetadata metadata3 = new MethodMetadata(method3);
+ manager.register(metadata3, interceptor);
+
+ MyComponent component = new MyComponent();
+ manager.start();
+ manager.load();
+ CountDownLatch startSignal = new CountDownLatch(1);
+ CountDownLatch doneSignal = new CountDownLatch(CALLERS);
+ for (int i = 1; i < CALLERS + 1; ++i) {
+ // create and start threads
+ executor.execute(new Caller(manager, component,
+ metadata1.getMethodIdentifier(), startSignal, doneSignal, i));
+ executor.execute(new Caller(manager, component,
+ metadata2.getMethodIdentifier(), startSignal, doneSignal, i));
+ executor.execute(new Caller(manager, component,
+ metadata3.getMethodIdentifier(), startSignal, doneSignal, i));
+ }
+
+ startSignal.countDown(); // let all threads proceed
+ assertThat(doneSignal.await(1, TimeUnit.MINUTES)).isTrue();
+ assertThat(error.get()).isEqualTo(0);
+ }
+
+ private class Caller implements Runnable {
+
+ private final CountDownLatch startSignal;
+ private final CountDownLatch doneSignal;
+ private final int id;
+ private final Object component;
+ private final String identifier;
+ private InstanceManager manager;
+
+ public Caller(InstanceManager manager, Object component, String identifier, CountDownLatch startSignal,
+ CountDownLatch doneSignal, int name) {
+ this.startSignal = startSignal;
+ this.doneSignal = doneSignal;
+ this.id = name;
+ this.manager = manager;
+ this.component = component;
+ this.identifier = identifier;
+ }
+
+ public void run() {
+ try {
+ startSignal.await();
+ manager.onEntry(component, identifier, new String[] {Integer.toString(id)});
+ manager.onExit(component, identifier, null);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ doneSignal.countDown();
+ }
+ }
+ }
+
+
+ private class MyComponent {
+
+ public void foo(String name) {
+ System.out.println(name);
+ }
+
+ public void bar(String name) {
+ System.out.println(name);
+ }
+
+ public void baz(String name) {
+ System.out.println(name);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/configuration/InstanceDSLTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/configuration/InstanceDSLTest.java
new file mode 100644
index 0000000..5d4c93e
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/configuration/InstanceDSLTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.configuration;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.extender.internal.processor.ConfigurationProcessor;
+
+import static org.apache.felix.ipojo.configuration.Instance.*;
+
+/**
+ * Check the instance DSL.
+ */
+public class InstanceDSLTest extends TestCase {
+
+
+ public void testInstance() {
+ instance().of("my.factory")
+ .with("simple").setto("simple");
+
+ instance()
+ .of("my.factory")
+ .with("simple").setto("simple")
+
+ .with("list").setto(list(1, 2, 3))
+ .with("list2").setto(list().with(1).with(2).with(3))
+
+ .with("map").setto(map().with(pair("entry", "value")))
+ .with("map").setto(map().with(pair("entry2", list("aaa", "bbb"))))
+ .with("map").setto(map().with(pair("key", 1), pair("key2", 2)))
+ .with("map").setto(map().with(entry("key", 1), entry("key2", 2)));
+ }
+
+ public void testClassnameExtraction() {
+ String cn = ConfigurationProcessor.getClassNameFromResource("/org/apache/felix/ipojo/Pojo.class");
+ Assert.assertEquals(cn, "org.apache.felix.ipojo.Pojo");
+ }
+
+ /**
+ * Test for FELIX-4490.
+ */
+ public void testInstanceNameNotNullOrEmpty() {
+ try {
+ instance().named(null);
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ instance().named("");
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ instance().nameIfUnnamed(null);
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ instance().nameIfUnnamed("");
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ instance().with("instance.name").setto(null);
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+
+ try {
+ instance().with("instance.name").setto("");
+ Assert.fail("Exception expected");
+ } catch (IllegalArgumentException e) {
+ // OK
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/impl/DependencyPropertiesTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/impl/DependencyPropertiesTest.java
new file mode 100644
index 0000000..7f3a024
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/impl/DependencyPropertiesTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.dependency.impl;
+
+import org.apache.felix.framework.FilterImpl;
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.*;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Checks the interceptor matching pattern.
+ */
+public class DependencyPropertiesTest {
+
+ private DependencyModel dependency;
+
+ @Before
+ public void setup() {
+ Bundle bundle = mock(Bundle.class);
+ when(bundle.getSymbolicName()).thenReturn("test-bundle");
+ when(bundle.getVersion()).thenReturn(new Version(1, 0, 0));
+
+ BundleContext context = mock(BundleContext.class);
+ when(context.getBundle()).thenReturn(bundle);
+
+ ComponentFactory factory = mock(ComponentFactory.class);
+ when(factory.getFactoryName()).thenReturn("FooFactory");
+
+ ComponentInstance instance = mock(ComponentInstance.class);
+ when(instance.getInstanceName()).thenReturn("FooConsumer");
+ when(instance.getState()).thenReturn(2);
+ when(instance.getFactory()).thenReturn(factory);
+
+ this.dependency = mock(DependencyModel.class);
+ when(dependency.getId()).thenReturn("foo");
+ when(dependency.getSpecification()).thenReturn(List.class);
+ when(dependency.getBundleContext()).thenReturn(context);
+ when(dependency.getComponentInstance()).thenReturn(instance);
+ when(dependency.getState()).thenReturn(0);
+
+ }
+
+ @Test
+ public void testDependencyCreation() {
+ Dictionary<String, ?> dictionary = DependencyProperties.getDependencyProperties(dependency);
+ assertThat(dictionary.get("dependency.id")).isEqualTo("foo");
+ assertThat(dictionary.get("dependency.specification")).isEqualTo(List.class.getName());
+ assertThat(dictionary.get("bundle.symbolicName")).isEqualTo("test-bundle");
+ }
+
+
+ @Test
+ public void matchByDependencyId() throws InvalidSyntaxException {
+ Dictionary<String, ?> dictionary = DependencyProperties.getDependencyProperties(dependency);
+ Filter filter = new FilterImpl("(dependency.id=foo)");
+ assertThat(filter.match(dictionary));
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReferenceTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReferenceTest.java
new file mode 100644
index 0000000..d77e405
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/dependency/interceptors/TransformedServiceReferenceTest.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.dependency.interceptors;
+
+import org.apache.felix.ipojo.dependency.impl.TransformedServiceReferenceImpl;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests service reference transformation
+ */
+public class TransformedServiceReferenceTest {
+
+ @Test
+ public void addPropertyToReference() {
+ ServiceReference reference = mock(ServiceReference.class);
+ when(reference.getPropertyKeys()).thenReturn(new String[] {"service.id", "foo"});
+ when(reference.getProperty("service.id")).thenReturn(42);
+ when(reference.getProperty("foo")).thenReturn("test");
+
+ ServiceReference newReference = new TransformedServiceReferenceImpl(reference).addProperty("location",
+ "kitchen");
+
+ assertThat(newReference.getPropertyKeys()).contains("location");
+ assertThat(newReference.getProperty("location")).isEqualTo("kitchen");
+ }
+
+ @Test
+ public void removePropertyToReference() {
+ ServiceReference<List> reference = mock(ServiceReference.class);
+ when(reference.getPropertyKeys()).thenReturn(new String[] {"service.id", "foo"});
+ when(reference.getProperty("service.id")).thenReturn(42l);
+ when(reference.getProperty("foo")).thenReturn("test");
+
+ ServiceReference newReference = new TransformedServiceReferenceImpl<List>(reference).removeProperty("foo");
+
+ assertThat(newReference.getPropertyKeys()).containsOnly("service.id");
+ assertThat(newReference.getProperty("foo")).isNull();
+ }
+
+ @Test
+ public void equals() {
+ ServiceReference<List> reference = mock(ServiceReference.class);
+ when(reference.getPropertyKeys()).thenReturn(new String[] {"service.id", "foo"});
+ when(reference.getProperty("service.id")).thenReturn((long) 42);
+ when(reference.getProperty("foo")).thenReturn("test");
+
+ ServiceReference newReference1 = new TransformedServiceReferenceImpl<List>(reference).removeProperty("foo");
+ ServiceReference newReference2 = new TransformedServiceReferenceImpl<List>(reference).removeProperty("foo");
+
+ assertThat(newReference1).isEqualTo(newReference2);
+ }
+
+ @Test
+ public void list() {
+ ServiceReference<List> reference = mock(ServiceReference.class);
+ when(reference.getPropertyKeys()).thenReturn(new String[] {"service.id", "foo"});
+ when(reference.getProperty("service.id")).thenReturn(42);
+ when(reference.getProperty("foo")).thenReturn("test");
+
+ ServiceReference newReference1 = new TransformedServiceReferenceImpl<List>(reference).removeProperty("foo");
+ ServiceReference newReference2 = new TransformedServiceReferenceImpl<List>(reference).removeProperty("foo");
+
+ List<ServiceReference> references = new ArrayList<ServiceReference>();
+ references.add(newReference1);
+
+ assertThat(references.contains(newReference1));
+ assertThat(references.contains(reference));
+ assertThat(references.contains(newReference2));
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclarationTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclarationTestCase.java
new file mode 100644
index 0000000..61e29ee
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultExtensionDeclarationTestCase.java
@@ -0,0 +1,66 @@
+/*
+ * 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.extender.internal.declaration;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the behavior of the devault extension declaration.
+ */
+public class DefaultExtensionDeclarationTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testRegistration() throws Exception {
+ m_bundleContext = mock(BundleContext.class);
+ DefaultExtensionDeclaration declaration = new DefaultExtensionDeclaration(m_bundleContext, null, "component");
+
+ // Before start, declaration is not bound
+ assertFalse(declaration.getStatus().isBound());
+ declaration.start();
+
+ // After start, declaration is bound
+ assertTrue(declaration.getStatus().isBound());
+
+ // Verify service registration
+ ArgumentCaptor<Hashtable> argument = ArgumentCaptor.forClass(Hashtable.class);
+ verify(m_bundleContext).registerService(eq(ExtensionDeclaration.class.getName()), eq(declaration), argument.capture());
+ assertEquals(argument.getValue().get(ExtensionDeclaration.EXTENSION_NAME_PROPERTY), "component");
+
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java
new file mode 100644
index 0000000..cc81f0d
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java
@@ -0,0 +1,132 @@
+/*
+ * 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.extender.internal.declaration;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the behavior of the default instance declaration.
+ */
+public class DefaultInstanceDeclarationTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private ServiceRegistration<?> m_registration;
+
+ @Captor
+ private ArgumentCaptor<Hashtable<String, Object>> argument;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(m_registration)
+ .when(m_bundleContext)
+ .registerService(
+ eq(InstanceDeclaration.class.getName()),
+ anyObject(),
+ any(Dictionary.class));
+
+ }
+
+ public void testRegistrationWithEmptyConfiguration() throws Exception {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+ declaration.start();
+
+ // Declaration is not bound
+ assertFalse(declaration.getStatus().isBound());
+
+ // Verify service registration
+ verify(m_bundleContext).registerService(eq(InstanceDeclaration.class.getName()), eq(declaration), argument.capture());
+ assertEquals(argument.getValue().get(InstanceDeclaration.COMPONENT_NAME_PROPERTY), "component.Hello");
+ assertNull(argument.getValue().get(InstanceDeclaration.COMPONENT_VERSION_PROPERTY));
+
+ }
+
+ public void testRegistrationWithVersionedConfiguration() throws Exception {
+ Hashtable<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put(Factory.FACTORY_VERSION_PROPERTY, "1.0.0");
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello", configuration);
+
+ declaration.start();
+
+ // Declaration is not bound
+ assertFalse(declaration.getStatus().isBound());
+
+ // Verify service registration
+ verify(m_bundleContext).registerService(eq(InstanceDeclaration.class.getName()), eq(declaration), argument.capture());
+ assertEquals(argument.getValue().get(InstanceDeclaration.COMPONENT_NAME_PROPERTY), "component.Hello");
+ assertEquals(argument.getValue().get(InstanceDeclaration.COMPONENT_VERSION_PROPERTY), "1.0.0");
+
+ }
+
+ public void testHandlePublication() throws Exception {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+ declaration.publish();
+ assertTrue(declaration.isRegistered());
+ }
+
+ public void testHandleMultiplePublication() throws Exception {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+ declaration.publish();
+ assertTrue(declaration.isRegistered());
+ declaration.publish();
+ assertTrue(declaration.isRegistered());
+ }
+
+ public void testHandleRetraction() throws Exception {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+ declaration.publish();
+ assertTrue(declaration.isRegistered());
+ declaration.retract();
+ assertFalse(declaration.isRegistered());
+ verify(m_registration).unregister();
+ }
+
+ public void testHandleMultipleRetraction() throws Exception {
+ DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+ declaration.publish();
+ assertTrue(declaration.isRegistered());
+ declaration.retract();
+ assertFalse(declaration.isRegistered());
+ declaration.retract();
+ assertFalse(declaration.isRegistered());
+ verify(m_registration).unregister();
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclarationTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclarationTestCase.java
new file mode 100644
index 0000000..acf123b
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultTypeDeclarationTestCase.java
@@ -0,0 +1,81 @@
+/*
+ * 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.extender.internal.declaration;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.IPojoFactory;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Checks the behavior of {@link TypeDeclaration}.
+ */
+public class DefaultTypeDeclarationTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+ @Mock
+ private Filter filter;
+ @Mock
+ private ServiceReference extensionReference;
+ @Mock
+ private ExtensionDeclaration m_extension;
+ @Mock
+ private FactoryBuilder m_builder;
+ @Mock
+ private IPojoFactory factory;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testRegistration() throws Exception {
+ when(m_bundleContext.createFilter(anyString())).thenReturn(filter);
+
+ DefaultTypeDeclaration declaration = new DefaultTypeDeclaration(m_bundleContext, element("component", "component.Hello"));
+ declaration.start();
+
+ // Declaration is not bound
+ assertFalse(declaration.getStatus().isBound());
+
+ // Verify service registration
+ verify(m_bundleContext).registerService(TypeDeclaration.class.getName(), declaration, null);
+
+ }
+
+ private Element element(String type, String name) {
+ Element root = new Element(type, null);
+ root.addAttribute(new Attribute("name", name));
+ return root;
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java
new file mode 100644
index 0000000..3edb304
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java
@@ -0,0 +1,100 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 11:33
+ */
+public class DefaultConfigurationBuilderTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+ private DefaultInstanceBuilder parent;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ parent = new DefaultInstanceBuilder(m_bundleContext, "type");
+ }
+
+ public void testPropertyAddition() throws Exception {
+ DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+ builder.property("a", "b");
+ InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+ assertEquals(declaration.getConfiguration().get("a"), "b");
+ }
+
+ public void testPropertyAdditionReUse() throws Exception {
+ DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+ builder.property("a", "b");
+
+ // First built instance
+ InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+ assertEquals(declaration.getConfiguration().get("a"), "b");
+
+ // Second built instance
+ builder.property("c", "d");
+ InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+ assertEquals(declaration2.getConfiguration().get("a"), "b");
+ assertEquals(declaration2.getConfiguration().get("c"), "d");
+
+ // Verify that first instance is not modified
+ assertNull(declaration.getConfiguration().get("c"));
+
+ }
+
+ public void testPropertyRemoval() throws Exception {
+ DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+ builder.property("a", "b");
+
+ InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+ assertEquals(declaration.getConfiguration().get("a"), "b");
+
+ builder.remove("a");
+
+ InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+ assertNull(declaration2.getConfiguration().get("a"));
+
+ }
+
+ public void testClear() throws Exception {
+ DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+ builder.property("a", "b");
+ builder.property("c", "d");
+
+ InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+ assertEquals(declaration.getConfiguration().get("a"), "b");
+
+ builder.clear();
+
+ InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+ assertTrue(declaration2.getConfiguration().isEmpty());
+
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java
new file mode 100644
index 0000000..87bf9c4
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java
@@ -0,0 +1,96 @@
+/*
+ * 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.extender.internal.declaration.service;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 10/02/2014
+ * Time: 15:41
+ */
+public class DefaultDeclarationBuilderServiceTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private FactoryBuilder m_factoryBuilder;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testNewInstance() throws Exception {
+ DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+ assertNotNull(service.newInstance("type.of.component"));
+ assertNotNull(service.newInstance("type.of.component", "instance.name"));
+ InstanceBuilder builder = service.newInstance("type.of.component", "instance.name", "component.version");
+ assertNotNull(builder);
+ DeclarationHandle instance = builder.build();
+ instance.publish();
+ verify(m_bundleContext).registerService(
+ eq(InstanceDeclaration.class.getName()),
+ anyObject(),
+ any(Dictionary.class));
+ }
+
+ public void testNewExtension() throws Exception {
+ DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+ DeclarationHandle extension = service.newExtension("test", m_factoryBuilder);
+ assertNotNull(extension);
+ extension.publish();
+ verify(m_bundleContext).registerService(
+ eq(ExtensionDeclaration.class.getName()),
+ anyObject(),
+ any(Dictionary.class));
+ }
+
+ public void testNewType() throws Exception {
+ DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+ DeclarationHandle type = service.newType(new Element("component", null));
+ assertNotNull(type);
+ type.publish();
+ verify(m_bundleContext).registerService(
+ eq(TypeDeclaration.class.getName()),
+ anyObject(),
+ isNull(Dictionary.class));
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java
new file mode 100644
index 0000000..abc5c73
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java
@@ -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.felix.ipojo.extender.internal.declaration.service;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 10:32
+ */
+public class DefaultInstanceBuilderTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testNoConfiguration() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+ DeclarationHandle handle = builder.build();
+ InstanceDeclaration did = (InstanceDeclaration) handle;
+
+ assertEquals("type", did.getComponentName());
+ assertEquals(InstanceDeclaration.UNNAMED_INSTANCE, did.getInstanceName());
+ assertNull(did.getComponentVersion());
+
+ Dictionary<String,Object> configuration = did.getConfiguration();
+ assertTrue(configuration.isEmpty());
+ }
+
+ public void testNameConfiguration() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type").name("John");
+
+ DeclarationHandle handle = builder.build();
+ InstanceDeclaration did = (InstanceDeclaration) handle;
+
+ assertEquals("type", did.getComponentName());
+ assertEquals("John", did.getInstanceName());
+ assertNull(did.getComponentVersion());
+
+ Dictionary<String,Object> configuration = did.getConfiguration();
+ assertEquals("John", configuration.get(Factory.INSTANCE_NAME_PROPERTY));
+ }
+
+ public void testVersionConfiguration() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type").name("John").version("1.0");
+
+ DeclarationHandle handle = builder.build();
+ InstanceDeclaration did = (InstanceDeclaration) handle;
+
+ assertEquals("type", did.getComponentName());
+ assertEquals("John", did.getInstanceName());
+ assertEquals("1.0", did.getComponentVersion());
+
+ Dictionary<String,Object> configuration = did.getConfiguration();
+ assertEquals("John", configuration.get(Factory.INSTANCE_NAME_PROPERTY));
+ assertEquals("1.0", configuration.get(Factory.FACTORY_VERSION_PROPERTY));
+ }
+
+ public void testBuilderReUseProvidesDifferentInstances() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+ assertNotSame(builder.build(), builder.build());
+ }
+
+
+ public void testDeclarationIsNotAutomaticallyStarted() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+ DeclarationHandle handle = builder.build();
+ DefaultInstanceDeclaration did = (DefaultInstanceDeclaration) handle;
+
+ assertFalse(did.isRegistered());
+ }
+
+ public void testDeepConfiguration() throws Exception {
+ InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+ assertNotNull(builder.configure());
+ }
+}
+
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinkerTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinkerTestCase.java
new file mode 100644
index 0000000..5845772
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/DeclarationLinkerTestCase.java
@@ -0,0 +1,116 @@
+/*
+ * 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.extender.internal.linker;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultTypeDeclaration;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the linker behavior.
+ */
+public class DeclarationLinkerTestCase extends TestCase {
+ @Mock
+ private Bundle m_bundle;
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private Filter filter;
+
+ @Mock
+ private ServiceReference m_reference;
+
+ @Mock
+ private QueueService m_queueService;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testActivationDeactivation() throws Exception {
+/*
+ when(filter.match(m_reference)).thenReturn(true);
+ when(m_bundleContext.getService(m_reference)).thenReturn(m_extension);
+ when(m_extension.getFactoryBuilder()).thenReturn(m_builder);
+ when(m_builder.build(any(BundleContext.class), any(Element.class))).thenReturn(factory);
+*/
+ when(m_bundleContext.getService(m_reference)).thenReturn(new DefaultTypeDeclaration(m_bundleContext, element("component", "test.Hello")));
+ when(m_bundleContext.createFilter(anyString())).thenReturn(filter);
+ when(m_reference.getBundle()).thenReturn(m_bundle);
+ when(m_bundle.getBundleContext()).thenReturn(m_bundleContext);
+
+ DeclarationLinker linker = new DeclarationLinker(m_bundleContext, m_queueService);
+ assertNotNull(linker.addingService(m_reference));
+
+/*
+ DefaultTypeDeclaration declaration = new DefaultTypeDeclaration(m_bundleContext, element("component", "component.Hello"));
+ declaration.start();
+
+ // Declaration is not bound
+ assertFalse(declaration.getStatus().isBound());
+
+ verify(m_bundleContext).addServiceListener(captor.capture(), anyString());
+
+ ServiceListener listener = captor.getValue();
+ ServiceEvent e = new ServiceEvent(ServiceEvent.REGISTERED, m_reference);
+ listener.serviceChanged(e);
+
+ verify(factory).addFactoryStateListener(fslCaptor.capture());
+ FactoryStateListener fsl = fslCaptor.getValue();
+ fsl.stateChanged(factory, Factory.VALID);
+
+ assertTrue(declaration.getStatus().isBound());
+
+ // The 2nd tracker should have registered its own listener
+ verify(m_bundleContext, times(2)).addServiceListener(captor.capture(), anyString());
+ ServiceListener listener2 = captor.getValue();
+ assertNotSame(listener, listener2);
+
+ ServiceEvent e2 = new ServiceEvent(ServiceEvent.UNREGISTERING, m_reference);
+ listener.serviceChanged(e2);
+
+ // After extension removal, the declaration should be unbound
+ assertFalse(declaration.getStatus().isBound());
+*/
+ }
+
+
+ private Element element(String type, String name) {
+ Element root = new Element(type, null);
+ root.addAttribute(new Attribute("name", name));
+ return root;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/ManagedTypeTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/ManagedTypeTestCase.java
new file mode 100644
index 0000000..cde431f
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/linker/ManagedTypeTestCase.java
@@ -0,0 +1,99 @@
+/*
+ * 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.extender.internal.linker;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 10/06/13
+ * Time: 13:32
+ */
+public class ManagedTypeTestCase extends TestCase {
+
+ @Mock
+ private BundleContext bundleContext;
+ @Mock
+ private QueueService queueService;
+ @Mock
+ private TypeDeclaration declaration;
+ @Mock
+ private Filter filter;
+
+
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(bundleContext.createFilter(anyString())).thenReturn(filter);
+ }
+
+ public void testStartingManagedType() throws Exception {
+
+ String filterStr = String.format(
+ "(&(objectclass=%s)(%s=%s))",
+ ExtensionDeclaration.class.getName(),
+ ExtensionDeclaration.EXTENSION_NAME_PROPERTY,
+ "test"
+ );
+
+ when(declaration.getExtension()).thenReturn("test");
+ when(declaration.getComponentMetadata()).thenReturn(element("test", "f.q.n.Type"));
+ when(declaration.getComponentName()).thenReturn("Type");
+ when(filter.toString()).thenReturn(filterStr);
+
+ ManagedType managedType = new ManagedType(bundleContext, queueService, declaration);
+ managedType.start();
+
+ verify(bundleContext).getAllServiceReferences(null, filterStr);
+
+ // Check that the filter contains a logical OR with component's name and classname
+ verify(bundleContext).createFilter(
+ contains(
+ String.format("(|(%s=%s)(%s=%s))",
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ "Type",
+ InstanceDeclaration.COMPONENT_NAME_PROPERTY,
+ "f.q.n.Type")
+ )
+ );
+ }
+
+ private Element element(String type, String classname) {
+ Element root = new Element(type, null);
+ root.addAttribute(new Attribute("classname", classname));
+ return root;
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessorTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessorTestCase.java
new file mode 100644
index 0000000..0ba895c
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ChainedBundleProcessorTestCase.java
@@ -0,0 +1,76 @@
+/*
+ * 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.extender.internal.processor;
+
+import static org.mockito.Mockito.inOrder;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the behavior of the chained bundle processor.
+ */
+public class ChainedBundleProcessorTestCase extends TestCase {
+
+ @Mock
+ private BundleProcessor m_delegate1;
+
+ @Mock
+ private BundleProcessor m_delegate2;
+
+ @Mock
+ private Bundle m_bundle;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testActivationThenDeactivateAreCalledWithReversedProcessorsList() throws Exception {
+ ChainedBundleProcessor chain = ChainedBundleProcessor.create(m_delegate1, m_delegate2);
+
+ chain.activate(m_bundle);
+ chain.deactivate(m_bundle);
+
+ InOrder order = inOrder(m_delegate1, m_delegate2);
+ order.verify(m_delegate1).activate(m_bundle);
+ order.verify(m_delegate2).activate(m_bundle);
+ order.verify(m_delegate2).deactivate(m_bundle);
+ order.verify(m_delegate1).deactivate(m_bundle);
+ }
+
+ public void testStartStopIsCalledWithReversedProcessorsList() throws Exception {
+ ChainedBundleProcessor chain = ChainedBundleProcessor.create(m_delegate1, m_delegate2);
+
+ chain.start();
+ chain.stop();
+
+ InOrder order = inOrder(m_delegate1, m_delegate2);
+ order.verify(m_delegate1).start();
+ order.verify(m_delegate2).start();
+ order.verify(m_delegate2).stop();
+ order.verify(m_delegate1).stop();
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessorTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessorTestCase.java
new file mode 100644
index 0000000..b87f8c0
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ExtensionBundleProcessorTestCase.java
@@ -0,0 +1,79 @@
+/*
+ * 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.extender.internal.processor;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.util.Logger;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+/**
+ * Tests the extension bundle processor.
+ */
+public class ExtensionBundleProcessorTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+ @Mock
+ private Logger m_logger;
+ @Mock
+ private Bundle m_bundle;
+
+ @Override
+ public void setUp() throws Exception {
+ Dictionary<String, String> headers = new Hashtable<String, String>();
+ MockitoAnnotations.initMocks(this);
+
+ when(m_bundle.getBundleContext()).thenReturn(m_bundleContext);
+ when(m_bundleContext.getBundle()).thenReturn(m_bundle);
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ }
+
+ public void testEmptyExtensionBundle() throws Exception {
+ ExtensionBundleProcessor processor = new ExtensionBundleProcessor(m_logger);
+ processor.activate(m_bundle);
+ verify(m_bundleContext, never()).registerService((Class<?>) null, null, null);
+ }
+
+ public void testSimpleExtensionBundle() throws Exception {
+ Dictionary<String, String> headers = new Hashtable<String, String>();
+ headers.put(ExtensionBundleProcessor.IPOJO_EXTENSION, "component:" + ComponentFactory.class.getName());
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ Mockito.<Class<?>>when(m_bundle.loadClass(anyString())).thenReturn(ComponentFactory.class);
+
+ ExtensionBundleProcessor processor = new ExtensionBundleProcessor(m_logger);
+ processor.activate(m_bundle);
+ verify(m_bundleContext).registerService(eq(ExtensionDeclaration.class.getName()), any(ExtensionDeclaration.class), any(Dictionary.class));
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessorTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessorTestCase.java
new file mode 100644
index 0000000..7a7ded2
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/processor/ReverseBundleProcessorTestCase.java
@@ -0,0 +1,84 @@
+/*
+ * 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.extender.internal.processor;
+
+import org.apache.felix.ipojo.extender.internal.BundleProcessor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the behavior of the reverse bundle processor.
+ */
+public class ReverseBundleProcessorTestCase extends TestCase {
+
+ @Mock
+ private Bundle m_bundle1;
+
+ @Mock
+ private Bundle m_bundle2;
+
+ @Mock
+ private Bundle m_bundle3;
+
+ @Mock
+ private BundleProcessor m_delegate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testReverseOrderWhenStopped() throws Exception {
+ ReverseBundleProcessor reverse = new ReverseBundleProcessor(m_delegate);
+ reverse.activate(m_bundle1);
+ reverse.activate(m_bundle2);
+ reverse.activate(m_bundle3);
+
+ reverse.stop();
+
+ InOrder order = Mockito.inOrder(m_delegate);
+ order.verify(m_delegate).deactivate(m_bundle3);
+ order.verify(m_delegate).deactivate(m_bundle2);
+ order.verify(m_delegate).deactivate(m_bundle1);
+
+ }
+
+ public void testReverseOrderWhenStoppedAndRemovedElements() throws Exception {
+ ReverseBundleProcessor reverse = new ReverseBundleProcessor(m_delegate);
+ reverse.activate(m_bundle1);
+ reverse.activate(m_bundle2);
+ reverse.activate(m_bundle3);
+
+ reverse.deactivate(m_bundle2);
+
+ reverse.stop();
+
+ InOrder order = Mockito.inOrder(m_delegate);
+ order.verify(m_delegate).deactivate(m_bundle2);
+ order.verify(m_delegate).deactivate(m_bundle3);
+ order.verify(m_delegate).deactivate(m_bundle1);
+
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueServiceTestCase.java
new file mode 100644
index 0000000..4da391d
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/AbstractQueueServiceTestCase.java
@@ -0,0 +1,133 @@
+/*
+ * 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.extender.internal.queue;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import static org.mockito.Mockito.verify;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 01/10/13
+ * Time: 16:36
+ */
+public class AbstractQueueServiceTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private JobInfo m_info;
+
+ @Mock
+ private QueueListener m_one;
+
+ @Mock
+ private QueueListener m_two;
+
+ private AbstractQueueService m_queueService;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ m_queueService = new TestableAbstractQueueService(m_bundleContext, QueueService.class);
+ }
+
+ public void testFireEnlistedJobInfo() throws Exception {
+ m_queueService.addQueueListener(m_one);
+ m_queueService.addQueueListener(m_two);
+ m_queueService.fireEnlistedJobInfo(m_info);
+ verify(m_one).enlisted(m_info);
+ verify(m_two).enlisted(m_info);
+ }
+
+ public void testFireStartedJobInfo() throws Exception {
+ m_queueService.addQueueListener(m_one);
+ m_queueService.addQueueListener(m_two);
+ m_queueService.fireStartedJobInfo(m_info);
+ verify(m_one).started(m_info);
+ verify(m_two).started(m_info);
+ }
+
+ public void testFireExecutedJobInfo() throws Exception {
+ m_queueService.addQueueListener(m_one);
+ m_queueService.addQueueListener(m_two);
+ m_queueService.fireExecutedJobInfo(m_info, "hello");
+ verify(m_one).executed(m_info, "hello");
+ verify(m_two).executed(m_info, "hello");
+ }
+
+ public void testFireFailedJobInfo() throws Exception {
+ m_queueService.addQueueListener(m_one);
+ m_queueService.addQueueListener(m_two);
+ Exception throwable = new Exception();
+ m_queueService.fireFailedJobInfo(m_info, throwable);
+ verify(m_one).failed(m_info, throwable);
+ verify(m_two).failed(m_info, throwable);
+ }
+
+ private class TestableAbstractQueueService extends AbstractQueueService {
+
+ public TestableAbstractQueueService(final BundleContext bundleContext, final Class<?> type) {
+ super(bundleContext, type);
+ }
+
+ public int getFinished() {
+ return 0;
+ }
+
+ public int getWaiters() {
+ return 0;
+ }
+
+ public int getCurrents() {
+ return 0;
+ }
+
+ public List<JobInfo> getWaitersInfo() {
+ return null;
+ }
+
+ public <T> Future<T> submit(final Job<T> callable, final Callback<T> callback, final String description) {
+ return null;
+ }
+
+ public <T> Future<T> submit(final Job<T> callable, final String description) {
+ return null;
+ }
+
+ public <T> Future<T> submit(final Job<T> callable) {
+ return null;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueServiceTestCase.java
new file mode 100644
index 0000000..5f11da1
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/ExecutorQueueServiceTestCase.java
@@ -0,0 +1,205 @@
+/*
+ * 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.extender.internal.queue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.Future;
+
+import org.apache.felix.ipojo.extender.internal.queue.callable.SleepingCallable;
+import org.apache.felix.ipojo.extender.internal.queue.callable.StringCallable;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the Executor Queue Service.
+ */
+public class ExecutorQueueServiceTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private ServiceRegistration<?> m_registration;
+
+ @Mock
+ private Callback<String> m_callback;
+
+ @Captor
+ private ArgumentCaptor<Dictionary<String, ?>> m_captor;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testQueueServiceRegistration() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext);
+
+ Mockito.<ServiceRegistration<?>>when(m_bundleContext.registerService(any(String[].class), eq(queueService), any(Dictionary.class))).thenReturn(m_registration);
+
+ queueService.start();
+
+ verify(m_bundleContext).registerService(any(String[].class), eq(queueService), any(Dictionary.class));
+
+ queueService.stop();
+
+ verify(m_registration).unregister();
+
+ }
+
+ public void testCallbackIsInvoked() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext);
+ queueService.start();
+
+ Future<String> future = queueService.submit(new StringCallable(), m_callback, "hello");
+
+ // Wait for callable to finish
+ assertEquals("hello", future.get());
+ verify(m_callback).success(any(JobInfo.class), eq("hello"));
+ verify(m_callback, never()).error(any(JobInfo.class), any(Exception.class));
+
+ queueService.stop();
+ }
+
+ public void testStatistics() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext, 2);
+ queueService.start();
+
+ // Ensure we start at 0
+ assertEquals(0, queueService.getWaiters());
+ assertEquals(0, queueService.getCurrents());
+ assertEquals(0, queueService.getFinished());
+
+ // We create 4 job, so that we have the 2 first executed while the 2 others are waiting
+ Future<String> one = queueService.submit(new SleepingCallable(50, "1"), m_callback, "First");
+ Future<String> two = queueService.submit(new SleepingCallable(50, "2"), m_callback, "Second");
+ Future<String> three = queueService.submit(new SleepingCallable(50, "3"), m_callback, "Third");
+ Future<String> four = queueService.submit(new SleepingCallable(50, "4"), m_callback, "Fourth");
+
+ // Wait for callable to finish
+ one.get();
+ two.get();
+
+ // Minimal assertion (do not test exact values)
+ assertTrue(queueService.getCurrents() > 0);
+ assertTrue(queueService.getFinished() > 0);
+
+ three.get();
+ four.get();
+
+ // Note: we cannot assert statistics reliably during the jobs execution: since when one
+ // is finished, another queued one will be executed in a row...
+ // So we have to wait until the end of all executions and hope for the best.
+
+ assertEquals(4, queueService.getFinished());
+ assertEquals(0, queueService.getCurrents());
+ assertEquals(0, queueService.getWaiters());
+
+ queueService.stop();
+ }
+
+ public void testConfigurationUpdate() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext, 1);
+
+ Mockito.<ServiceRegistration<?>>when(m_bundleContext.registerService(any(String[].class),
+ eq(queueService),
+ any(Dictionary.class)))
+ .thenReturn(m_registration);
+
+ queueService.start();
+
+ verify(m_bundleContext).registerService(any(String[].class), eq(queueService), m_captor.capture());
+
+ // Verify initial value is 1
+ Dictionary<String, ?> initial = m_captor.getValue();
+ assertEquals(1, initial.get(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY));
+
+ Dictionary<String, Object> update = new Hashtable<String, Object>();
+ update.put(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY, 3);
+ queueService.updated(update);
+
+ verify(m_registration).setProperties(m_captor.capture());
+ assertEquals(3, m_captor.getValue().get(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY));
+ }
+
+ public void testManagedServiceUpdatedWithNull() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext, 1);
+
+ Mockito.<ServiceRegistration<?>>when(m_bundleContext.registerService(any(String[].class),
+ eq(queueService),
+ any(Dictionary.class)))
+ .thenReturn(m_registration);
+
+ queueService.start();
+
+ verify(m_bundleContext).registerService(any(String[].class), eq(queueService), m_captor.capture());
+
+ // Verify initial value is 1
+ Dictionary<String, ?> initial = m_captor.getValue();
+ assertEquals(1, initial.get(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY));
+
+ // Change the value once and then apply a null configuration
+ // Service should use it's default configuration
+ Dictionary<String, Object> update = new Hashtable<String, Object>();
+ update.put(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY, 3);
+ queueService.updated(update);
+ queueService.updated(null);
+
+ verify(m_registration, times(2)).setProperties(m_captor.capture());
+ assertEquals(1, m_captor.getValue().get(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY));
+ }
+
+ public void testConfigurationUpdatedWithNoChanges() throws Exception {
+ ExecutorQueueService queueService = new ExecutorQueueService(m_bundleContext, 1);
+
+ Mockito.<ServiceRegistration<?>>when(m_bundleContext.registerService(any(String[].class),
+ eq(queueService),
+ any(Dictionary.class)))
+ .thenReturn(m_registration);
+
+ queueService.start();
+
+ Dictionary<String, Object> update = new Hashtable<String, Object>();
+ update.put(ExecutorQueueService.THREADPOOL_SIZE_PROPERTY, 1);
+ queueService.updated(update);
+
+ verifyZeroInteractions(m_registration);
+ }
+}
+
+
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactoryTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactoryTestCase.java
new file mode 100644
index 0000000..93834bc
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/GroupThreadFactoryTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * 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.extender.internal.queue;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 30/09/13
+ * Time: 15:37
+ */
+public class GroupThreadFactoryTestCase extends TestCase {
+
+ public void testThreadsAreInTheSpecifiedGroup() throws Exception {
+ ThreadGroup group = new ThreadGroup("Test");
+ GroupThreadFactory factory = new GroupThreadFactory(group);
+
+ Thread thread = factory.newThread(new EmptyRunnable());
+
+ assertEquals(group, thread.getThreadGroup());
+ }
+
+ private static class EmptyRunnable implements Runnable {
+ public void run() {
+ // do nothing
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallableTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallableTestCase.java
new file mode 100644
index 0000000..34594d3
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/JobInfoCallableTestCase.java
@@ -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.
+ */
+
+package org.apache.felix.ipojo.extender.internal.queue;
+
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.apache.felix.ipojo.extender.internal.queue.callable.ExceptionCallable;
+import org.apache.felix.ipojo.extender.internal.queue.callable.StringCallable;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the job info callable.
+ */
+public class JobInfoCallableTestCase extends TestCase {
+
+ @Mock
+ private QueueNotifier m_notifier;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testCall() throws Exception {
+ Statistic stat = new Statistic();
+ long mark = System.currentTimeMillis();
+ JobInfoCallable<String> info = new JobInfoCallable<String>(m_notifier, stat, new StringCallable(), null, null);
+
+ // Before execution
+ assertTrue(info.getEnlistmentTime() >= mark);
+ assertEquals(-1, info.getExecutionDuration());
+ assertTrue(info.getWaitDuration() <= (System.currentTimeMillis() - mark));
+
+ assertTrue(stat.getWaiters().contains(info));
+ assertEquals(0, stat.getCurrentsCounter().get());
+ assertEquals(0, stat.getFinishedCounter().get());
+
+ info.call();
+
+ assertTrue(info.getExecutionDuration() != -1);
+
+ assertTrue(stat.getWaiters().isEmpty());
+ assertEquals(0, stat.getCurrentsCounter().get());
+ assertEquals(1, stat.getFinishedCounter().get());
+
+ InOrder order = Mockito.inOrder(m_notifier);
+ order.verify(m_notifier).fireEnlistedJobInfo(info);
+ order.verify(m_notifier).fireStartedJobInfo(info);
+ order.verify(m_notifier).fireExecutedJobInfo(info, "hello");
+ verifyNoMoreInteractions(m_notifier);
+
+ }
+
+ public void testFailedCall() throws Exception {
+ Statistic stat = new Statistic();
+ Exception e = new Exception();
+ JobInfoCallable<String> info = new JobInfoCallable<String>(m_notifier, stat, new ExceptionCallable(e), null, null);
+
+ try {
+ info.call();
+ } catch (Exception e1) {
+ InOrder order = Mockito.inOrder(m_notifier);
+ order.verify(m_notifier).fireEnlistedJobInfo(info);
+ order.verify(m_notifier).fireStartedJobInfo(info);
+ order.verify(m_notifier).fireFailedJobInfo(info, e);
+ verifyNoMoreInteractions(m_notifier);
+ return;
+ }
+
+ fail("Should have throw an Exception");
+
+ }
+
+ public void testJobInfoType() throws Exception {
+ JobInfoCallable<String> info = new JobInfoCallable<String>(m_notifier, new Statistic(), new StringCallable("ipojo.testJobType", "hello"), null, null);
+ assertEquals("ipojo.testJobType", info.getJobType());
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactoryTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactoryTestCase.java
new file mode 100644
index 0000000..c9bd2bd
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/NamingThreadFactoryTestCase.java
@@ -0,0 +1,89 @@
+/*
+ * 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.extender.internal.queue;
+
+import java.util.concurrent.ThreadFactory;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 30/09/13
+ * Time: 15:46
+ */
+public class NamingThreadFactoryTestCase extends TestCase {
+
+ @Override
+ public void setUp() throws Exception {
+ // Ensure pool numbering starts at 1 for each test
+ NamingThreadFactory.reset();
+ }
+
+ public void testSequentialThreadNaming() throws Exception {
+ NamingThreadFactory factory = new NamingThreadFactory(new DefaultThreadFactory());
+
+ Thread t1 = factory.newThread(new EmptyRunnable());
+ Thread t2 = factory.newThread(new EmptyRunnable());
+ Thread t3 = factory.newThread(new EmptyRunnable());
+ Thread t4 = factory.newThread(new EmptyRunnable());
+
+ assertEquals("pool-1-thread-1", t1.getName());
+ assertEquals("pool-1-thread-2", t2.getName());
+ assertEquals("pool-1-thread-3", t3.getName());
+ assertEquals("pool-1-thread-4", t4.getName());
+ }
+
+ public void testMultiThreadNamingFactories() throws Exception {
+ NamingThreadFactory factory1 = new NamingThreadFactory(new DefaultThreadFactory());
+ NamingThreadFactory factory2 = new NamingThreadFactory(new DefaultThreadFactory());
+
+ // Interleaved invocations
+ Thread t21 = factory2.newThread(new EmptyRunnable());
+ Thread t11 = factory1.newThread(new EmptyRunnable());
+ Thread t12 = factory1.newThread(new EmptyRunnable());
+ Thread t13 = factory1.newThread(new EmptyRunnable());
+ Thread t22 = factory2.newThread(new EmptyRunnable());
+ Thread t23 = factory2.newThread(new EmptyRunnable());
+ Thread t14 = factory1.newThread(new EmptyRunnable());
+ Thread t24 = factory2.newThread(new EmptyRunnable());
+
+ assertEquals("pool-1-thread-1", t11.getName());
+ assertEquals("pool-1-thread-2", t12.getName());
+ assertEquals("pool-1-thread-3", t13.getName());
+ assertEquals("pool-1-thread-4", t14.getName());
+
+ assertEquals("pool-2-thread-1", t21.getName());
+ assertEquals("pool-2-thread-2", t22.getName());
+ assertEquals("pool-2-thread-3", t23.getName());
+ assertEquals("pool-2-thread-4", t24.getName());
+ }
+
+ private static class DefaultThreadFactory implements ThreadFactory {
+ public Thread newThread(final Runnable r) {
+ return new Thread(r);
+ }
+ }
+
+ private static class EmptyRunnable implements Runnable {
+ public void run() {
+ // do nothing
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactoryTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactoryTestCase.java
new file mode 100644
index 0000000..e101ee1
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/PrefixedThreadFactoryTestCase.java
@@ -0,0 +1,48 @@
+/*
+ * 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.extender.internal.queue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.ThreadFactory;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the behavior of the {@link PrefixedThreadFactory}.
+ */
+public class PrefixedThreadFactoryTestCase extends TestCase {
+ public void testNewThread() throws Exception {
+ PrefixedThreadFactory factory = new PrefixedThreadFactory("test ");
+ Thread t = factory.newThread(mock(Runnable.class));
+ assertTrue(t.getName().startsWith("test "));
+ }
+ public void testNewThreadDelegation() throws Exception {
+ ThreadFactory delegate = mock(ThreadFactory.class);
+ when(delegate.newThread(any(Runnable.class))).thenReturn(new Thread("thread"));
+ PrefixedThreadFactory factory = new PrefixedThreadFactory(delegate, "test ");
+ Thread t = factory.newThread(mock(Runnable.class));
+ verify(delegate).newThread(any(Runnable.class));
+ assertEquals(t.getName(), "test thread");
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueServiceTestCase.java
new file mode 100644
index 0000000..cb2bf37
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/SynchronousQueueServiceTestCase.java
@@ -0,0 +1,96 @@
+/*
+ * 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.extender.internal.queue;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.extender.internal.queue.callable.StringCallable;
+import org.apache.felix.ipojo.extender.queue.Callback;
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the synchronous queue behavior
+ */
+public class SynchronousQueueServiceTestCase extends TestCase {
+
+ @Mock
+ private BundleContext m_bundleContext;
+
+ @Mock
+ private ServiceRegistration<?> m_registration;
+
+ @Mock
+ private Callback<String> m_callback;
+
+ @Captor
+ private ArgumentCaptor<JobInfo> infos;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testRegistration() throws Exception {
+ SynchronousQueueService queueService = new SynchronousQueueService(m_bundleContext);
+
+ Mockito.<ServiceRegistration<?>>when(m_bundleContext.registerService(eq(QueueService.class.getName()), eq(queueService), any(Dictionary.class))).thenReturn(m_registration);
+
+ queueService.start();
+
+ verify(m_bundleContext).registerService(eq(QueueService.class.getName()), eq(queueService), any(Dictionary.class));
+
+ queueService.stop();
+
+ verify(m_registration).unregister();
+ }
+
+ public void testSubmitsAreSequential() throws Exception {
+
+ SynchronousQueueService queueService = new SynchronousQueueService(m_bundleContext);
+
+ queueService.submit(new StringCallable("one"), m_callback, null);
+ queueService.submit(new StringCallable("two"), m_callback, null);
+
+ InOrder order = inOrder(m_callback);
+ order.verify(m_callback).success(infos.capture(), eq("one"));
+ order.verify(m_callback).success(infos.capture(), eq("two"));
+
+ JobInfo one = infos.getAllValues().get(0);
+ JobInfo two = infos.getAllValues().get(1);
+
+ assertTrue(two.getEnlistmentTime() >= one.getEndTime());
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/EmptyJob.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/EmptyJob.java
new file mode 100644
index 0000000..5ab1759
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/EmptyJob.java
@@ -0,0 +1,59 @@
+/*
+ * 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.extender.internal.queue.callable;
+
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.osgi.framework.Bundle;
+
+/**
+ * User: guillaume
+ * Date: 01/10/13
+ * Time: 17:51
+ */
+public class EmptyJob<T> implements Job<T> {
+
+ private final Bundle m_bundle;
+ private final String m_type;
+
+ public EmptyJob() {
+ this(null);
+ }
+
+ public EmptyJob(final Bundle bundle) {
+ this(bundle, "test");
+ }
+
+ public EmptyJob(Bundle bundle, String type) {
+ m_bundle = bundle;
+ m_type = type;
+ }
+
+ public String getJobType() {
+ return m_type;
+ }
+
+ public Bundle getBundle() {
+ return m_bundle;
+ }
+
+ public T call() throws Exception {
+ return null;
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/ExceptionCallable.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/ExceptionCallable.java
new file mode 100644
index 0000000..162c778
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/ExceptionCallable.java
@@ -0,0 +1,38 @@
+/*
+ * 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.extender.internal.queue.callable;
+
+import java.util.concurrent.Callable;
+
+/**
+* A dummy job.
+*/
+public class ExceptionCallable extends EmptyJob<String> {
+
+ private final Exception m_exception;
+
+ public ExceptionCallable(Exception e) {
+ m_exception = e;
+ }
+
+ public String call() throws Exception {
+ throw m_exception;
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/SleepingCallable.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/SleepingCallable.java
new file mode 100644
index 0000000..dfe98a2
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/SleepingCallable.java
@@ -0,0 +1,40 @@
+/*
+ * 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.extender.internal.queue.callable;
+
+import java.util.concurrent.Callable;
+
+/**
+* A dummy job taking some time to complete....
+*/
+public class SleepingCallable extends EmptyJob<String> {
+ private int m_time;
+ private String m_value;
+
+ public SleepingCallable(int time, String value) {
+ m_time = time;
+ m_value = value;
+ }
+
+ public String call() throws Exception {
+ Thread.sleep(m_time);
+ return m_value;
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/StringCallable.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/StringCallable.java
new file mode 100644
index 0000000..776f4e3
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/callable/StringCallable.java
@@ -0,0 +1,63 @@
+/*
+ * 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.extender.internal.queue.callable;
+
+import java.util.concurrent.Callable;
+
+import org.apache.felix.ipojo.extender.queue.Job;
+import org.osgi.framework.Bundle;
+
+/**
+* A dummy job.
+*/
+public class StringCallable extends EmptyJob<String> {
+
+ private final String m_hello;
+
+ public StringCallable() {
+ this((Bundle) null, "hello");
+ }
+
+ public StringCallable(String value) {
+ this((Bundle) null, value);
+ }
+
+ public StringCallable(String type, String value) {
+ this(null, type, value);
+ }
+
+ public StringCallable(Bundle bundle) {
+ this(bundle, "hello");
+ }
+
+ public StringCallable(Bundle bundle, String hello) {
+ super(bundle);
+ m_hello = hello;
+ }
+
+ public StringCallable(Bundle bundle, String type, String hello) {
+ super(bundle, type);
+ m_hello = hello;
+ }
+
+ public String call() throws Exception {
+ return m_hello;
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxyTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxyTestCase.java
new file mode 100644
index 0000000..3253ef9
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/debug/ReplayQueueEventProxyTestCase.java
@@ -0,0 +1,122 @@
+/*
+ * 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.extender.internal.queue.debug;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.apache.felix.ipojo.extender.queue.JobInfo;
+import org.apache.felix.ipojo.extender.queue.QueueListener;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 02/10/13
+ * Time: 12:01
+ */
+public class ReplayQueueEventProxyTestCase extends TestCase {
+
+ @Mock
+ private JobInfo m_info1;
+
+ @Mock
+ private JobInfo m_info2;
+
+ @Mock
+ private QueueListener m_listener;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testEventsAreReplayedOnListenerAddition() throws Exception {
+ ReplayQueueEventProxy proxy = new ReplayQueueEventProxy();
+
+ proxy.enlisted(m_info1);
+ proxy.started(m_info1);
+ proxy.enlisted(m_info2);
+ proxy.executed(m_info1, "hello");
+ proxy.started(m_info2);
+ Exception throwable = new Exception();
+ proxy.failed(m_info2, throwable);
+
+ proxy.addQueueListener(m_listener);
+
+ verify(m_listener).enlisted(m_info1);
+ verify(m_listener).started(m_info1);
+ verify(m_listener).executed(m_info1, "hello");
+ verify(m_listener).enlisted(m_info2);
+ verify(m_listener).started(m_info2);
+ verify(m_listener).failed(m_info2, throwable);
+
+ }
+
+ public void testNoEventsAreSendAfterListenerRemoval() throws Exception {
+ ReplayQueueEventProxy proxy = new ReplayQueueEventProxy();
+
+ proxy.enlisted(m_info1);
+ proxy.started(m_info1);
+
+ proxy.addQueueListener(m_listener);
+
+ proxy.enlisted(m_info2);
+
+ proxy.removeQueueListener(m_listener);
+
+ proxy.executed(m_info1, "hello");
+ proxy.started(m_info2);
+ Exception throwable = new Exception();
+ proxy.failed(m_info2, throwable);
+
+ // Ensure no methods are called after removal
+ verify(m_listener).enlisted(m_info1);
+ verify(m_listener).started(m_info1);
+ verify(m_listener).enlisted(m_info2);
+ verifyNoMoreInteractions(m_listener);
+
+ }
+
+ public void testEventsAreForwarded() throws Exception {
+ ReplayQueueEventProxy proxy = new ReplayQueueEventProxy();
+
+ proxy.enlisted(m_info1);
+ proxy.started(m_info1);
+
+ proxy.addQueueListener(m_listener);
+
+ proxy.enlisted(m_info2);
+ proxy.executed(m_info1, "hello");
+ proxy.started(m_info2);
+ Exception throwable = new Exception();
+ proxy.failed(m_info2, throwable);
+
+ verify(m_listener).enlisted(m_info1);
+ verify(m_listener).started(m_info1);
+ verify(m_listener).executed(m_info1, "hello");
+ verify(m_listener).enlisted(m_info2);
+ verify(m_listener).started(m_info2);
+ verify(m_listener).failed(m_info2, throwable);
+
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelectionTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelectionTestCase.java
new file mode 100644
index 0000000..c187928
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/HeaderPreferenceSelectionTestCase.java
@@ -0,0 +1,79 @@
+/*
+ * 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.extender.internal.queue.pref;
+
+import static org.mockito.Mockito.when;
+
+import java.util.Hashtable;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the selection of the job processing preference from the bundle manifest.
+ */
+public class HeaderPreferenceSelectionTestCase extends TestCase {
+
+ public static final String HEADER = "Header";
+
+ @Mock
+ private Bundle m_bundle;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testMissingHeader() throws Exception {
+ Hashtable<String, String> headers = new Hashtable<String, String>();
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ HeaderPreferenceSelection selection = new HeaderPreferenceSelection(HEADER);
+ assertEquals(Preference.DEFAULT, selection.select(m_bundle));
+ }
+
+ public void testUnrecognizedHeader() throws Exception {
+ Hashtable<String, String> headers = new Hashtable<String, String>();
+ headers.put(HEADER, "invalid");
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ HeaderPreferenceSelection selection = new HeaderPreferenceSelection(HEADER);
+ assertEquals(Preference.DEFAULT, selection.select(m_bundle));
+ }
+
+ public void testSyncHeader() throws Exception {
+ Hashtable<String, String> headers = new Hashtable<String, String>();
+ // We should ignore case
+ headers.put(HEADER, "SyNc");
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ HeaderPreferenceSelection selection = new HeaderPreferenceSelection(HEADER);
+ assertEquals(Preference.SYNC, selection.select(m_bundle));
+ }
+
+ public void testAsyncHeader() throws Exception {
+ Hashtable<String, String> headers = new Hashtable<String, String>();
+ // We should ignore case
+ headers.put(HEADER, "aSyNc");
+ when(m_bundle.getHeaders()).thenReturn(headers);
+ HeaderPreferenceSelection selection = new HeaderPreferenceSelection(HEADER);
+ assertEquals(Preference.ASYNC, selection.select(m_bundle));
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueServiceTestCase.java
new file mode 100644
index 0000000..900de1a
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/queue/pref/enforce/EnforcedQueueServiceTestCase.java
@@ -0,0 +1,88 @@
+/*
+ * 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.extender.internal.queue.pref.enforce;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.Callable;
+
+import org.apache.felix.ipojo.extender.internal.DefaultJob;
+import org.apache.felix.ipojo.extender.internal.LifecycleQueueService;
+import org.apache.felix.ipojo.extender.internal.queue.callable.StringCallable;
+import org.apache.felix.ipojo.extender.internal.queue.pref.Preference;
+import org.apache.felix.ipojo.extender.internal.queue.pref.PreferenceSelection;
+import org.apache.felix.ipojo.extender.queue.QueueService;
+import org.apache.felix.ipojo.util.Log;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleReference;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks the enforced queue service.
+ */
+public class EnforcedQueueServiceTestCase extends TestCase {
+
+ @Mock
+ private LifecycleQueueService delegate;
+
+ @Mock
+ private Bundle m_bundle;
+
+ @Mock
+ private Log m_log;
+
+ @Mock
+ private PreferenceSelection m_selection;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testNoEnforcement() throws Exception {
+ when(m_selection.select(m_bundle)).thenReturn(Preference.DEFAULT);
+ EnforcedQueueService queueService = new EnforcedQueueService(m_selection, delegate, Preference.ASYNC, m_log);
+ queueService.submit(new StringCallable(m_bundle));
+ verifyZeroInteractions(m_log);
+ }
+
+ public void testIncompatibleEnforcement() throws Exception {
+ when(m_selection.select(m_bundle)).thenReturn(Preference.SYNC);
+ EnforcedQueueService queueService = new EnforcedQueueService(m_selection, delegate, Preference.ASYNC, m_log);
+ queueService.submit(new StringCallable(m_bundle));
+
+ verify(m_log).log(eq(Log.WARNING), anyString());
+ }
+
+ public void testCompatibleEnforcement() throws Exception {
+ when(m_selection.select(m_bundle)).thenReturn(Preference.ASYNC);
+ EnforcedQueueService queueService = new EnforcedQueueService(m_selection, delegate, Preference.ASYNC, m_log);
+ queueService.submit(new StringCallable(m_bundle));
+ verifyZeroInteractions(m_log);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/DependencyIdentifierTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/DependencyIdentifierTest.java
new file mode 100644
index 0000000..ca78718
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/DependencyIdentifierTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.handlers.dependency;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Checks the dependency identifier computation.
+ */
+public class DependencyIdentifierTest {
+
+ @Test
+ public void testDependencyWithAllInformation() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getId()).thenReturn("id1");
+ Mockito.when(dependency.getField()).thenReturn("fs");
+ DependencyCallback[] callbacks = new DependencyCallback[2];
+ callbacks[0] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[0].getMethodName()).thenReturn("bindFooService");
+ callbacks[1] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[1].getMethodName()).thenReturn("unbindFooService");
+ Mockito.when(dependency.getCallbacks()).thenReturn(callbacks);
+ Mockito.when(dependency.getSpecification()).thenReturn(List.class);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).startsWith("{");
+ assertThat(identifier).endsWith("}");
+ assertThat(identifier).contains("id=" + "id1");
+ assertThat(identifier).contains("field=" + "fs");
+ assertThat(identifier).contains("specification=" + List.class.getName());
+ assertThat(identifier).contains("method=" + "bindFooService");
+
+ System.out.println(identifier);
+ }
+
+ @Test
+ public void testDependencyWithIdOnly() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getId()).thenReturn("id1");
+ Mockito.when(dependency.getField()).thenReturn(null);
+ Mockito.when(dependency.getCallbacks()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).startsWith("{");
+ assertThat(identifier).endsWith("}");
+ assertThat(identifier).contains("id=" + "id1");
+ assertThat(identifier).isEqualTo("{id=" + "id1}");
+ assertThat(identifier).doesNotContain("field");
+ assertThat(identifier).doesNotContain("specification");
+ assertThat(identifier).doesNotContain("method");
+ }
+
+ @Test
+ public void testDependencyWithFieldOnly() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn("fs");
+ Mockito.when(dependency.getId()).thenReturn(null);
+ Mockito.when(dependency.getCallbacks()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{field=" + "fs}");
+ }
+
+ @Test
+ public void testDependencyWithSpecificationOnly() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn(null);
+ Mockito.when(dependency.getId()).thenReturn(null);
+ Mockito.when(dependency.getCallbacks()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(List.class);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{specification=" + List.class.getName() + "}");
+ }
+
+ @Test
+ public void testDependencyWithNothing() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn(null);
+ Mockito.when(dependency.getId()).thenReturn(null);
+ Mockito.when(dependency.getCallbacks()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{}");
+ }
+
+ @Test
+ public void testDependencyWithCallbackOnly() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn(null);
+ Mockito.when(dependency.getId()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+ DependencyCallback[] callbacks = new DependencyCallback[2];
+ callbacks[0] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[0].getMethodName()).thenReturn("bindFooService");
+ callbacks[1] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[1].getMethodName()).thenReturn("unbindFooService");
+ Mockito.when(dependency.getCallbacks()).thenReturn(callbacks);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{method=bindFooService}");
+ }
+
+ @Test
+ public void testDependencyWithIdAndField() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn("fs");
+ Mockito.when(dependency.getId()).thenReturn("id1");
+ Mockito.when(dependency.getCallbacks()).thenReturn(null);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{id=id1, field=fs}");
+ }
+
+ @Test
+ public void testDependencyWithFieldAndMethod() {
+ Dependency dependency = Mockito.mock(Dependency.class);
+ Mockito.when(dependency.getField()).thenReturn("fs");
+ Mockito.when(dependency.getId()).thenReturn(null);
+ DependencyCallback[] callbacks = new DependencyCallback[2];
+ callbacks[0] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[0].getMethodName()).thenReturn("bindFooService");
+ callbacks[1] = Mockito.mock(DependencyCallback.class);
+ Mockito.when(callbacks[1].getMethodName()).thenReturn("unbindFooService");
+ Mockito.when(dependency.getCallbacks()).thenReturn(callbacks);
+ Mockito.when(dependency.getSpecification()).thenReturn(null);
+
+ String identifier = DependencyHandler.getDependencyIdentifier(dependency);
+ assertThat(identifier).isEqualTo("{field=fs, method=bindFooService}");
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/NullableTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/NullableTest.java
new file mode 100644
index 0000000..ffa5c33
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/NullableTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.handlers.dependency;
+
+import java.lang.reflect.Proxy;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.handlers.providedservice.ComponentTestWithSuperClass;
+import org.apache.felix.ipojo.test.MockBundle;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class NullableTest extends TestCase {
+
+ public void testOnGet_whenNullableEnabled_returnsAnInstanceOfNullableAndSpecification() {
+ Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
+ BundleContext context = Mockito.mock(BundleContext.class);
+ InstanceManager im = Mockito.mock(InstanceManager.class);
+ Mockito.when(im.getClazz()).thenReturn(ComponentTestWithSuperClass.class);
+ DependencyHandler handler = Mockito.mock(DependencyHandler.class);
+ Mockito.when(handler.getInstanceManager()).thenReturn(im);
+ Dependency dependency = new Dependency(handler, "a_field", TestSpecification.class, null, true, false, true,
+ false, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+
+ Object service = dependency.onGet(null, null, null);
+
+ Assert.assertTrue(service instanceof Nullable);
+ Assert.assertTrue(service instanceof TestSpecification);
+ }
+
+ public void testOnGet_whenNullableEnabled_returnsAProxyWithNullableObjectAsInvocationHandler() {
+ Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
+ BundleContext context = Mockito.mock(BundleContext.class);
+ InstanceManager im = Mockito.mock(InstanceManager.class);
+ Mockito.when(im.getClazz()).thenReturn(ComponentTestWithSuperClass.class);
+ DependencyHandler handler = Mockito.mock(DependencyHandler.class);
+ Mockito.when(handler.getInstanceManager()).thenReturn(im);
+ Dependency dependency = new Dependency(handler, "a_field", TestSpecification.class, null, true, false, true,
+ false, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+
+ Object service = dependency.onGet(null, null, null);
+
+ Assert.assertTrue(service instanceof Proxy);
+ Assert.assertTrue(Proxy.getInvocationHandler(service) instanceof NullableObject);
+ }
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java
new file mode 100644
index 0000000..927317d
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.handlers.dependency;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.test.MockBundle;
+import org.apache.felix.ipojo.util.Logger;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SmartProxyTest extends TestCase {
+
+ public void setUp() {
+ }
+
+
+ /**
+ * Check that we don't create smart proxies for concrete and abstract classes.
+ */
+ public void testCannotProxyAbstractAndConcreteClasses() {
+ Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
+
+ BundleContext context = (BundleContext) Mockito.mock(BundleContext.class);
+ Mockito.when(context.getProperty(DependencyHandler.PROXY_TYPE_PROPERTY)).thenReturn(null);
+ Mockito.when(context.getProperty(Logger.IPOJO_LOG_LEVEL_PROP)).thenReturn(null);
+ Mockito.when(context.getBundle()).thenReturn(bundle);
+
+ ComponentFactory factory = (ComponentFactory) Mockito.mock(ComponentFactory.class);
+ Mockito.when(factory.getBundleClassLoader()).thenReturn(Dependency.class.getClassLoader());
+
+ InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ Mockito.when(im.getContext()).thenReturn(context);
+ Mockito.when(im.getFactory()).thenReturn(factory);
+
+ DependencyHandler handler = (DependencyHandler) Mockito.mock(DependencyHandler.class);
+ Mockito.when(handler.getInstanceManager()).thenReturn(im);
+ Logger logger = new Logger(context, "test", Logger.INFO);
+
+
+ Mockito.when(handler.getLogger()).thenReturn(logger);
+
+ Dependency dependency = new Dependency(handler, "a_field", ArrayList.class, null, false, false, false,
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+
+ // No service
+ Assert.assertNull(dependency.onGet(new Object(), "a_field", null));
+
+ dependency.stop();
+
+ // Try with an Object.
+ dependency = new Dependency(handler, "a_field", Object.class, null, false, false, false,
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+ // OK
+ Assert.assertNull(dependency.onGet(new Object(), "a_field", null));
+ }
+
+ /**
+ * Tests if we can proxies classes from java.* package.
+ * Indeed, a recent JVM bug fix introduces a bug:
+ * <code>
+ * [ERROR] test : Cannot create the proxy object
+ * java.lang.SecurityException: Prohibited package name: java.awt
+ * </code>
+ */
+ public void testProxiesOfJavaClasses() {
+ Bundle bundle = new MockBundle(Dependency.class.getClassLoader());
+
+ BundleContext context = (BundleContext) Mockito.mock(BundleContext.class);
+ Mockito.when(context.getProperty(DependencyHandler.PROXY_TYPE_PROPERTY)).thenReturn(null);
+ Mockito.when(context.getProperty(Logger.IPOJO_LOG_LEVEL_PROP)).thenReturn(null);
+ Mockito.when(context.getBundle()).thenReturn(bundle);
+
+ ComponentFactory factory = (ComponentFactory) Mockito.mock(ComponentFactory.class);
+ Mockito.when(factory.getBundleClassLoader()).thenReturn(Dependency.class.getClassLoader());
+
+ InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ Mockito.when(im.getContext()).thenReturn(context);
+ Mockito.when(im.getFactory()).thenReturn(factory);
+
+ DependencyHandler handler = (DependencyHandler) Mockito.mock(DependencyHandler.class);
+ Mockito.when(handler.getInstanceManager()).thenReturn(im);
+ Logger logger = new Logger(context, "test", Logger.INFO);
+
+
+ Mockito.when(handler.getLogger()).thenReturn(logger);
+
+ // Try with java.List
+ Dependency dependency = new Dependency(handler, "a_field", List.class, null, false, false, false,
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+
+ // OK
+ Assert.assertNotNull(dependency.onGet(new Object(), "a_field", null));
+ Assert.assertTrue(dependency.onGet(new Object(), "a_field", null) instanceof List);
+
+ dependency.stop();
+
+ // Try with javax.sql.CommonDataSource
+ dependency = new Dependency(handler, "a_field", javax.sql.DataSource.class, null, false, false, false,
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
+ dependency.start();
+ // OK
+ Assert.assertNotNull(dependency.onGet(new Object(), "a_field", null));
+ Assert.assertTrue(dependency.onGet(new Object(), "a_field", null) instanceof javax.sql.DataSource);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/TestSpecification.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/TestSpecification.java
new file mode 100644
index 0000000..0acd35a
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/TestSpecification.java
@@ -0,0 +1,24 @@
+/*
+ * 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.handlers.dependency;
+
+public interface TestSpecification
+{
+ String doSomething(String param);
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithAnotherSuperClass.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithAnotherSuperClass.java
new file mode 100644
index 0000000..ac98ec7
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithAnotherSuperClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.beans.MethodDescriptor;
+import java.lang.reflect.Method;
+
+public class ComponentTestWithAnotherSuperClass extends MethodDescriptor {
+
+ public ComponentTestWithAnotherSuperClass(Method method) {
+ super(method);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithSuperClass.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithSuperClass.java
new file mode 100644
index 0000000..55e456a
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ComponentTestWithSuperClass.java
@@ -0,0 +1,25 @@
+/*
+ * 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.handlers.providedservice;
+
+import java.beans.SimpleBeanInfo;
+
+public class ComponentTestWithSuperClass extends SimpleBeanInfo {
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerTest.java
new file mode 100644
index 0000000..fd39412
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandlerTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.handlers.providedservice;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.test.MockBundle;
+import org.apache.felix.ipojo.util.Logger;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Dictionary;
+import java.util.Properties;
+
+public class ProvidedServiceHandlerTest extends TestCase {
+
+ BundleContext context;
+ ComponentFactory factory;
+ InstanceManager im;
+ ComponentTypeDescription desc;
+ ProvidedServiceHandler handler;
+ Logger logger;
+
+ public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ context = (BundleContext) Mockito.mock(BundleContext.class);
+ Mockito.when(context.getProperty(DependencyHandler.PROXY_TYPE_PROPERTY)).thenReturn(null);
+ Mockito.when(context.getProperty(Logger.IPOJO_LOG_LEVEL_PROP)).thenReturn(null);
+ Mockito.when(context.getBundle()).thenReturn(new MockBundle(this.getClass().getClassLoader()));
+
+ factory = (ComponentFactory) Mockito.mock(ComponentFactory.class);
+ Mockito.when(factory.getBundleClassLoader()).thenReturn(ProvidedServiceHandler.class.getClassLoader());
+ logger = Mockito.spy(new Logger(context, "TEST", Logger.INFO));
+ Mockito.when(factory.getLogger()).thenReturn(logger);
+
+ im = (InstanceManager) Mockito.mock(InstanceManager.class);
+ Mockito.when(im.getContext()).thenReturn(context);
+ Mockito.when(im.getGlobalContext()).thenReturn(context);
+ Mockito.when(im.getFactory()).thenReturn(factory);
+ Mockito.when(im.getInstanceName()).thenReturn("an.instance");
+
+ desc = (ComponentTypeDescription) Mockito.mock(ComponentTypeDescription.class);
+ Mockito.when(desc.getFactory()).thenReturn(factory);
+ Mockito.when(desc.getBundleContext()).thenReturn(context);
+
+ handler = new ProvidedServiceHandler();
+ handler.setFactory(factory);
+
+ // Attach the handler
+ Method method = PrimitiveHandler.class.getDeclaredMethod("attach", new Class[]{ComponentInstance.class});
+ method.setAccessible(true);
+ method.invoke(handler, new Object[]{im});
+
+ }
+
+ public void testServiceDetectionNoInterface() throws ConfigurationException {
+ String classname = "org.apache.felix.ipojo.handlers.providedservice.ComponentTest";
+
+ Element metadata = new Element("component", "");
+ Element manipulation = new Element("manipulation", "");
+ metadata.addAttribute(new Attribute("classname", classname));
+ metadata.addElement(new Element("provides", ""));
+ metadata.addElement(manipulation);
+ manipulation.addAttribute(new Attribute("classname", classname));
+
+ Mockito.when(factory.getPojoMetadata()).thenReturn(new PojoMetadata(metadata));
+ Mockito.when(factory.getClassName()).thenReturn(classname);
+
+ handler.initializeComponentFactory(desc, metadata);
+
+ //Expected behavior: the implementation classname
+ Assert.assertEquals("{org.apache.felix.ipojo.handlers.providedservice.ComponentTest}",
+ metadata.getElements("provides")[0].getAttribute("specifications"));
+ }
+
+ public void testServiceDetectionSuperClass() throws ConfigurationException {
+ String classname = "org.apache.felix.ipojo.handlers.providedservice.ComponentTestWithSuperClass";
+
+ Element metadata = new Element("component", "");
+ Element manipulation = new Element("manipulation", "");
+ metadata.addAttribute(new Attribute("classname", classname));
+ Element provides = new Element("provides", "");
+ provides.addAttribute(new Attribute("specifications", "java.beans.SimpleBeanInfo"));
+ metadata.addElement(provides);
+ metadata.addElement(manipulation);
+ manipulation.addAttribute(new Attribute("classname", classname));
+ manipulation.addAttribute(new Attribute("super", "java.beans.SimpleBeanInfo"));
+ Mockito.when(factory.getPojoMetadata()).thenReturn(new PojoMetadata(metadata));
+ Mockito.when(factory.getClassName()).thenReturn(classname);
+
+ handler.initializeComponentFactory(desc, metadata);
+
+ System.out.println(metadata);
+
+ }
+
+ public void testServiceDetectionImplementationClass() throws ConfigurationException {
+ String classname = "org.apache.felix.ipojo.handlers.providedservice.ComponentTestWithSuperClass";
+
+ Element metadata = new Element("component", "");
+ Element manipulation = new Element("manipulation", "");
+ metadata.addAttribute(new Attribute("classname", classname));
+ Element provides = new Element("provides", "");
+ provides.addAttribute(new Attribute("specifications", classname));
+ metadata.addElement(provides);
+ metadata.addElement(manipulation);
+ manipulation.addAttribute(new Attribute("classname", classname));
+ manipulation.addAttribute(new Attribute("super", "java.beans.SimpleBeanInfo"));
+ Mockito.when(factory.getPojoMetadata()).thenReturn(new PojoMetadata(metadata));
+ Mockito.when(factory.getClassName()).thenReturn(classname);
+
+ handler.initializeComponentFactory(desc, metadata);
+
+ System.out.println(metadata);
+
+ }
+
+ public void testServiceDetectionSuperSuperClass() throws ConfigurationException {
+ String classname = "org.apache.felix.ipojo.handlers.providedservice.ComponentTestWithAnotherSuperClass";
+
+ Element metadata = new Element("component", "");
+ Element manipulation = new Element("manipulation", "");
+ metadata.addAttribute(new Attribute("classname", classname));
+ Element provides = new Element("provides", "");
+ provides.addAttribute(new Attribute("specifications", "java.beans.FeatureDescriptor"));
+ metadata.addElement(provides);
+ metadata.addElement(manipulation);
+ manipulation.addAttribute(new Attribute("classname", classname));
+ manipulation.addAttribute(new Attribute("super", "java.beans.MethodDescriptor"));
+
+ Mockito.when(factory.getPojoMetadata()).thenReturn(new PojoMetadata(metadata));
+ Mockito.when(factory.getClassName()).thenReturn(classname);
+
+ handler.initializeComponentFactory(desc, metadata);
+
+ System.out.println(metadata);
+
+ }
+
+ public void testWhenRequiresFilterIsPropagated() throws Exception {
+ Dictionary dictionary = new Properties();
+ Dictionary requiresfilter = new Properties();
+ requiresfilter.put("id1", "(filter1)");
+ dictionary.put("requires.filter", requiresfilter);
+
+
+ ProvidedService providedService = new ProvidedService(handler, new String[] {Runnable.class.getName()}, ProvidedService.SINGLETON_STRATEGY, null, new Properties());
+ Assert.assertEquals(2, providedService.getProperties().length); // instance.name, service.pid
+ providedService.addProperties(dictionary);
+
+ Assert.assertEquals(2 + 1, providedService.getProperties().length);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/ManipulationMetadataTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/ManipulationMetadataTest.java
new file mode 100644
index 0000000..7658320
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/ManipulationMetadataTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.jar.Manifest;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Check manipulation metadata written in the manifest.
+ */
+public class ManipulationMetadataTest extends TestCase {
+
+ private String header;
+
+ public void setUp() {
+ File manFile = new File("src/test/resources/manipulation/MANIFEST.MF");
+ Manifest manifest;
+ try {
+ manifest = new Manifest(new FileInputStream(manFile));
+ header = manifest.getMainAttributes().getValue("iPOJO-Components");
+ } catch (FileNotFoundException e) {
+ fail(e.getMessage());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testGetMetadata() {
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getManipulationForComponent(elem, "ManipulationMetadata-FooProviderType-1");
+ assertNotNull("Check manipulation metadata not null for " + "FooProviderType-1", manip);
+ }
+
+ public void testInterface() {
+ String comp_name = "ManipulationMetadata-FooProviderType-1";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] itf = manip.getElements("Interface");
+ assertEquals("Check interfaces number", itf.length, 1);
+ assertEquals("Check itf name", itf[0].getAttribute("name"),
+ "org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService");
+ }
+
+ public void testInterfaces() {
+ String comp_name = "ManipulationMetadata-FooBarProviderType-1";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] itf = manip.getElements("Interface");
+ assertEquals("Check interfaces number", itf.length, 2);
+ assertEquals("Check itf name", itf[0].getAttribute("name"),
+ "org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService");
+ assertEquals("Check itf name", itf[1].getAttribute("name"),
+ "org.apache.felix.ipojo.test.scenarios.manipulation.service.BarService");
+ }
+
+ public void testFields() {
+ String comp_name = "ManipulationMetadata-FooProviderType-Dyn";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] fields = manip.getElements("field");
+ assertEquals("Check field count " + fields.length, fields.length, 5);
+ /*
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+ */
+
+ Element field;
+
+ field = getFieldFromName(manip, "intProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "intProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int");
+
+ field = getFieldFromName(manip, "strProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "strProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "java.lang.String");
+
+ field = getFieldFromName(manip, "strAProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "strAProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "java.lang.String[]");
+
+ field = getFieldFromName(manip, "intAProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "intAProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int[]");
+
+ field = getFieldFromName(manip, "boolProp");
+ assertEquals("Check field name : " + field.getAttribute("name"), field.getAttribute("name"), "boolProp");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean");
+ }
+
+ public void testPrimitivesFields() {
+ String comp_name = "ManipulationMetadata-PrimitiveManipulationTester";
+ Element manip = getManipulationForComponent(comp_name);
+ Element[] fields = manip.getElements("Field");
+ assertEquals("Check field count", fields.length, 16);
+ /*
+ byte b = 1;
+ short s = 1;
+ int i = 1;
+ long l = 1;
+ double d = 1.1;
+ float f = 1.1f;
+ char c = 'a';
+ boolean bool = false;
+ byte[] bs = new byte[] {0,1,2};
+ short[] ss = new short[] {0,1,2};
+ int[] is = new int[] {0,1,2};
+ long[] ls = new long[] {0,1,2};
+ double[] ds = new double[] {0.0, 1.1, 2.2};
+ float[] fs = new float[] {0.0f, 1.1f, 2.2f};
+ char[] cs = new char[] {'a', 'b', 'c'};
+ boolean[] bools = new boolean[] {false, true, false};
+ */
+ Element field;
+
+ field = getFieldFromName(manip, "b");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "byte");
+ field = getFieldFromName(manip, "s");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "short");
+ field = getFieldFromName(manip, "i");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int");
+ field = getFieldFromName(manip, "l");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "long");
+ field = getFieldFromName(manip, "d");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "double");
+ field = getFieldFromName(manip, "f");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "float");
+ field = getFieldFromName(manip, "c");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "char");
+ field = getFieldFromName(manip, "bool");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean");
+
+ field = getFieldFromName(manip, "bs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "byte[]");
+ field = getFieldFromName(manip, "ss");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "short[]");
+ field = getFieldFromName(manip, "is");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "int[]");
+ field = getFieldFromName(manip, "ls");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "long[]");
+ field = getFieldFromName(manip, "ds");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "double[]");
+ field = getFieldFromName(manip, "fs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "float[]");
+ field = getFieldFromName(manip, "cs");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "char[]");
+ field = getFieldFromName(manip, "bools");
+ assertEquals("Check field type : " + field.getAttribute("name"), field.getAttribute("type"), "boolean[]");
+ }
+
+ public void testNoArgMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "check");
+ assertFalse("Check no args", method.containsAttribute("arguments"));
+ assertEquals("Check return", method.getAttribute("return"), "boolean");
+ }
+
+ public void testOneArgsMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "refBind");
+ assertEquals("Check args", method.getAttribute("arguments"), "{org.osgi.framework.ServiceReference}");
+ assertEquals("Check args count", 1, ParseUtils.parseArrays("{org.osgi.framework.ServiceReference}").length);
+ assertFalse("Check return", method.containsAttribute("return"));
+ }
+
+ public void testTwoArgsMethod() {
+ String comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ Element manip = getManipulationForComponent(comp_name);
+ Element method = getMethodFromName(manip, "doNothing");
+ assertEquals("Check args", method.getAttribute("arguments"), "{java.lang.Object,java.lang.String}");
+ assertEquals("Check args count", 2, ParseUtils.parseArrays("{java.lang.Object,java.lang.String}").length);
+ assertEquals("Check return", method.getAttribute("return"), "java.lang.Object");
+ }
+
+ private Element getManipulationForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for(int i = 0; i < comps.length; i++) {
+ if(comps[i].containsAttribute("factory") && comps[i].getAttribute("factory").equals(comp_name)) {
+ return comps[i].getElements("manipulation")[0];
+ }
+ if(comps[i].containsAttribute("name") && comps[i].getAttribute("name").equals(comp_name)) {
+ return comps[i].getElements("manipulation")[0];
+ }
+ }
+ return null;
+ }
+
+ private Element getManipulationForComponent(String comp_name) {
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+ Element manip = getManipulationForComponent(elem, comp_name);
+ assertNotNull("Check manipulation metadata not null for " + comp_name, manip);
+ return manip;
+ }
+
+ private Element getMethodFromName(Element manip, String name) {
+ Element methods[] = manip.getElements("Method");
+ for(int i = 0; i < methods.length; i++) {
+ if(methods[i].containsAttribute("name") && methods[i].getAttribute("name").equals(name)) {
+ return methods[i];
+ }
+ }
+ fail("Method " + name + " not found");
+ return null;
+ }
+
+ private Element getFieldFromName(Element manip, String name) {
+ Element fields[] = manip.getElements("Field");
+ for(int i = 0; i < fields.length; i++) {
+ if(fields[i].containsAttribute("name") && fields[i].getAttribute("name").equals(name)) {
+ return fields[i];
+ }
+ }
+ fail("Field " + name + " not found");
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/MethodMetadataTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/MethodMetadataTest.java
new file mode 100644
index 0000000..230b66b
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/MethodMetadataTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.parser;
+
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.lang.reflect.Method;
+
+public class MethodMetadataTest extends TestCase {
+
+ public void testIdComputationForArrays() throws NoSuchMethodException {
+ Method method = this.getClass().getMethod("withOneArray", new String[0].getClass());
+ String id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withOneArray$java_lang_String__", id);
+
+ method = this.getClass().getMethod("withDoubleArray", new String[0][0].getClass());
+ id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withDoubleArray$java_lang_String____", id);
+
+ method = this.getClass().getMethod("withTripleArray", new String[0][0][0].getClass());
+ id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withTripleArray$java_lang_String______", id);
+ }
+
+ public void testIdComputationForArraysUsingPrimitive() throws NoSuchMethodException {
+ Method method = this.getClass().getMethod("withPrimitiveArray", new int[0].getClass());
+ String id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withPrimitiveArray$int__", id);
+
+ method = this.getClass().getMethod("withPrimitiveArray", new int[0][0].getClass());
+ id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withPrimitiveArray$int____", id);
+
+ method = this.getClass().getMethod("withPrimitiveArray", new int[0][0][0].getClass());
+ id = MethodMetadata.computeMethodId(method);
+ Assert.assertEquals("withPrimitiveArray$int______", id);
+ }
+
+ public void testComputationForArraysUsingObjectsFromElement() {
+ Element metadata1 = new Element("method", null);
+ metadata1.addAttribute(new Attribute("name", "withOneArray"));
+ metadata1.addAttribute(new Attribute("arguments", "{java.lang.String[]}"));
+
+ Element metadata2 = new Element("method", null);
+ metadata2.addAttribute(new Attribute("name", "withOneArray"));
+ metadata2.addAttribute(new Attribute("arguments", "{java.lang.String[][]}"));
+
+ Element metadata3 = new Element("method", null);
+ metadata3.addAttribute(new Attribute("name", "withOneArray"));
+ metadata3.addAttribute(new Attribute("arguments", "{java.lang.String[][][]}"));
+
+ MethodMetadata methodMetadata1 = new MethodMetadata(metadata1);
+ Assert.assertEquals("withOneArray$java_lang_String__", methodMetadata1.getMethodIdentifier());
+
+ MethodMetadata methodMetadata2 = new MethodMetadata(metadata2);
+ Assert.assertEquals("withOneArray$java_lang_String____", methodMetadata2.getMethodIdentifier());
+
+ MethodMetadata methodMetadata3 = new MethodMetadata(metadata3);
+ Assert.assertEquals("withOneArray$java_lang_String______", methodMetadata3.getMethodIdentifier());
+ }
+
+ public void testComputationForArraysUsingPrimitiveFromElement() {
+ Element metadata1 = new Element("method", null);
+ metadata1.addAttribute(new Attribute("name", "withOneArray"));
+ metadata1.addAttribute(new Attribute("arguments", "{int[]}"));
+
+ Element metadata2 = new Element("method", null);
+ metadata2.addAttribute(new Attribute("name", "withOneArray"));
+ metadata2.addAttribute(new Attribute("arguments", "{int[][]}"));
+
+ Element metadata3 = new Element("method", null);
+ metadata3.addAttribute(new Attribute("name", "withOneArray"));
+ metadata3.addAttribute(new Attribute("arguments", "{int[][][]}"));
+
+ MethodMetadata methodMetadata1 = new MethodMetadata(metadata1);
+ Assert.assertEquals("withOneArray$int__", methodMetadata1.getMethodIdentifier());
+
+ MethodMetadata methodMetadata2 = new MethodMetadata(metadata2);
+ Assert.assertEquals("withOneArray$int____", methodMetadata2.getMethodIdentifier());
+
+ MethodMetadata methodMetadata3 = new MethodMetadata(metadata3);
+ Assert.assertEquals("withOneArray$int______", methodMetadata3.getMethodIdentifier());
+ }
+
+
+ // Method analyzed for testing
+
+ public void withOneArray(String[] arr) { }
+ public void withPrimitiveArray(int[] arr) { }
+ public void withDoubleArray(String[][] arr) { }
+ public void withPrimitiveArray(int[][] arr) { }
+ public void withPrimitiveArray(int[][][] arr) { }
+ public void withTripleArray(String[][][] arr) { }
+
+ public MethodMetadataTest() {
+ super();
+ }
+
+ // Constructor used for testing
+ public MethodMetadataTest(String[] arr) { }
+ public MethodMetadataTest(String[][] arr) { }
+ public MethodMetadataTest(int[] arr) { }
+ public MethodMetadataTest(int[][] arr) { }
+ public MethodMetadataTest(int[][][] arr) { }
+
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/PojoMetadataTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/PojoMetadataTest.java
new file mode 100644
index 0000000..050590f
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/parser/PojoMetadataTest.java
@@ -0,0 +1,322 @@
+/*
+ * 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.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.jar.Manifest;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class PojoMetadataTest extends TestCase {
+
+ PojoMetadata FooProviderType1, FooBarProviderType1, FooProviderTypeDyn, PrimitiveManipulationTester, SimpleMultipleCheckServiceProvider;
+
+ private String header;
+
+ public void setUp() {
+ File manFile = new File("src/test/resources/manipulation/MANIFEST.MF");
+ Manifest manifest;
+ try {
+ manifest = new Manifest(new FileInputStream(manFile));
+ header = manifest.getMainAttributes().getValue("iPOJO-Components");
+ } catch (FileNotFoundException e) {
+ fail(e.getMessage());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+
+ String comp_name = "ManipulationMetadata-FooProviderType-1";
+ FooProviderType1 = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-FooBarProviderType-1";
+ FooBarProviderType1 = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-FooProviderType-Dyn";
+ FooProviderTypeDyn = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-PrimitiveManipulationTester";
+ PrimitiveManipulationTester = getManipulationMetadataForComponent(comp_name);
+
+ comp_name = "ManipulationMetadata-SimpleMultipleCheckServiceProvider";
+ SimpleMultipleCheckServiceProvider = getManipulationMetadataForComponent(comp_name);
+ }
+
+ public void testGetMetadata() {
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ fail("Parse Exception when parsing iPOJO-Component");
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getMetadataForComponent(elem, "ManipulationMetadata-FooProviderType-1");
+ assertNotNull("Check manipulation metadata not null for " + "Manipulation-FooProviderType-1", manip);
+ PojoMetadata mm;
+ try {
+ mm = new PojoMetadata(manip);
+ assertNotNull("Check mm not null", mm);
+ } catch (ConfigurationException e) {
+ fail("The creation of pojo metadata has failed");
+ }
+ }
+
+ public void testInterface() {
+ PojoMetadata manip = FooProviderType1;
+
+ String[] itf = manip.getInterfaces();
+ assertEquals("Check interfaces number", itf.length, 1);
+ assertEquals("Check itf name", itf[0], "org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService");
+
+ assertTrue("Check Foo Service implementation", manip.isInterfaceImplemented("org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService"));
+ assertFalse("Check Bar Service implementation", manip.isInterfaceImplemented("org.apache.felix.ipojo.test.scenarios.manipulation.service.BarService"));
+ }
+
+ public void testInterfaces() {
+ PojoMetadata manip = FooBarProviderType1;
+ String[] itf = manip.getInterfaces();
+ assertEquals("Check interfaces number", itf.length, 2);
+ assertEquals("Check itf name", itf[0], "org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService");
+ assertEquals("Check itf name", itf[1], "org.apache.felix.ipojo.test.scenarios.manipulation.service.BarService");
+
+ assertTrue("Check Foo Service implementation", manip.isInterfaceImplemented("org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService"));
+ assertTrue("Check Bar Service implementation", manip.isInterfaceImplemented("org.apache.felix.ipojo.test.scenarios.manipulation.service.BarService"));
+ }
+
+ public void testFields() {
+ PojoMetadata manip = FooProviderTypeDyn;
+
+ FieldMetadata[] fields = manip.getFields();
+ assertEquals("Check field count + " + fields.length, fields.length, 5);
+ /*
+ private int intProp;
+ private String strProp;
+ private String[] strAProp;
+ private int[] intAProp;
+ private boolean boolProp;
+ */
+
+ FieldMetadata field;
+
+ field = manip.getField("intProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "int");
+
+ field = manip.getField("intProp", "int");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+
+ field = manip.getField("intProp", "long");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("strProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "java.lang.String");
+
+ field = manip.getField("strProp", "String");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("strProp", "java.lang.String");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String");
+
+ field = manip.getField("strAProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String[]");
+ assertEquals("Check field reflective type : " + field.getFieldName() + " -> " + FieldMetadata.getReflectionType(field.getFieldType()), FieldMetadata.getReflectionType(field.getFieldType()), "[Ljava.lang.String;");
+
+ field = manip.getField("strAProp", "java.lang.String[]");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "strAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "java.lang.String[]");
+
+ field = manip.getField("strAProp", "String[]");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("intAProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+ assertEquals("Check field reflective type : " + field.getFieldName() + " -> " + FieldMetadata.getReflectionType(field.getFieldType()), FieldMetadata.getReflectionType(field.getFieldType()), "[I");
+
+ field = manip.getField("intAProp", "int[]");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "intAProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+
+ field = manip.getField("intAProp", "String[]");
+ assertNull("Check bad field", field);
+
+ field = manip.getField("boolProp");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "boolProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+ assertEquals("Check field reflective type : " + field.getFieldName(), FieldMetadata.getReflectionType(field.getFieldType()), "boolean");
+
+ field = manip.getField("boolProp", "boolean");
+ assertEquals("Check field name : " + field.getFieldName(), field.getFieldName(), "boolProp");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+
+ field = manip.getField("boolProp", "bool");
+ assertNull("Check bad field", field);
+ }
+
+ public void testPrimitivesFields() {
+ PojoMetadata manip = PrimitiveManipulationTester;
+ FieldMetadata[] fields = manip.getFields();
+ assertEquals("Check field count", fields.length, 16);
+
+ FieldMetadata field;
+
+ field = manip.getField("b");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "byte");
+ field = manip.getField("s");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "short");
+ field = manip.getField("i");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int");
+ field = manip.getField("l");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "long");
+ field = manip.getField("d");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "double");
+ field = manip.getField("f");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "float");
+ field = manip.getField("c");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "char");
+ field = manip.getField("bool");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean");
+
+ field = manip.getField("bs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "byte[]");
+ field = manip.getField("ss");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "short[]");
+ field = manip.getField("is");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "int[]");
+ field = manip.getField("ls");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "long[]");
+ field = manip.getField("ds");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "double[]");
+ field = manip.getField("fs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "float[]");
+ field = manip.getField("cs");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "char[]");
+ field = manip.getField("bools");
+ assertEquals("Check field type : " + field.getFieldName(), field.getFieldType(), "boolean[]");
+ }
+
+ public void testNoArgMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethod("check");
+ assertEquals("Check no args", method.getMethodArguments().length, 0);
+ assertEquals("Check return", method.getMethodReturn(), "boolean");
+
+ method = manip.getMethod("check", new String[0]);
+ assertEquals("Check no args", method.getMethodArguments().length, 0);
+ assertEquals("Check return", method.getMethodReturn(), "boolean");
+ }
+
+ public void testOneArgsMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethods("refBind")[0];
+ assertEquals("Check args count", method.getMethodArguments().length, 1);
+ assertEquals("Check args", method.getMethodArguments()[0], "org.osgi.framework.ServiceReference");
+ assertEquals("Check return", method.getMethodReturn(), "void");
+
+ method = manip.getMethod("refBind", new String[] {"org.osgi.framework.ServiceReference"});
+ assertEquals("Check args count", method.getMethodArguments().length, 1);
+ assertEquals("Check args", method.getMethodArguments()[0], "org.osgi.framework.ServiceReference");
+ assertEquals("Check return", method.getMethodReturn(), "void");
+ }
+
+ public void testTwoArgsMethod() {
+ PojoMetadata manip = SimpleMultipleCheckServiceProvider;
+ MethodMetadata method = manip.getMethods("doNothing")[0];
+ assertEquals("Check args count", 2, method.getMethodArguments().length);
+ assertEquals("Check args - 1", method.getMethodArguments()[0], "java.lang.Object");
+ assertEquals("Check args - 2", method.getMethodArguments()[1], "java.lang.String");
+ assertEquals("Check return", method.getMethodReturn(), "java.lang.Object");
+
+ method = manip.getMethod("doNothing", new String[] {"java.lang.Object", "java.lang.String"});
+ assertEquals("Check args count", 2, method.getMethodArguments().length);
+ assertEquals("Check args - 1", method.getMethodArguments()[0], "java.lang.Object");
+ assertEquals("Check args - 2", method.getMethodArguments()[1], "java.lang.String");
+ assertEquals("Check return", method.getMethodReturn(), "java.lang.Object");
+ }
+
+ public void testSuper() {
+ String comp_name = "org.apache.felix.ipojo.test.scenarios.component.Child";
+ PojoMetadata manip = getManipulationMetadataForComponent(comp_name);
+ assertEquals("org.apache.felix.ipojo.test.scenarios.component.Parent", manip.getSuperClass());
+ assertEquals(1, manip.getConstructors().length);
+ }
+
+ public void testConstructors() {
+ String comp_name = "org.apache.felix.ipojo.test.scenarios.component.Multiconstructor";
+ PojoMetadata manip = getManipulationMetadataForComponent(comp_name);
+ assertEquals(3, manip.getConstructors().length);
+ assertNotNull(manip.getConstructor(new String[] {String.class.getName(), String.class.getName()}));
+ assertNotNull(manip.getConstructor(new String[] {String.class.getName(), String.class.getName(), Integer.TYPE.getName()}));
+ assertNotNull(manip.getConstructor(new String[] {String.class.getName(), Integer.TYPE.getName()}));
+ assertNull(manip.getConstructor(new String[] {String.class.getName()}));
+ }
+
+
+ private Element getMetadataForComponent(Element metadata, String comp_name) {
+ Element[] comps = metadata.getElements("component");
+ for(int i = 0; i < comps.length; i++) {
+ if(comps[i].containsAttribute("factory") && comps[i].getAttribute("factory").equals(comp_name)) {
+ return comps[i];
+ }
+ if(comps[i].containsAttribute("name") && comps[i].getAttribute("name").equals(comp_name)) {
+ return comps[i];
+ }
+ if(comps[i].containsAttribute("classname") && comps[i].getAttribute("classname").equals(comp_name)) {
+ return comps[i];
+ }
+ }
+ return null;
+ }
+
+
+ private PojoMetadata getManipulationMetadataForComponent(String comp_name) {
+ Element elem = null;
+ try {
+ elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ fail("Parse Exception when parsing iPOJO-Component " + e);
+ }
+
+ assertNotNull("Check elem not null", elem);
+
+ Element manip = getMetadataForComponent(elem, comp_name);
+ assertNotNull("Check manipulation metadata not null for " + comp_name, manip);
+ try {
+ return new PojoMetadata(manip);
+ } catch (ConfigurationException e) {
+ fail("The creation of pojo metadata for " + comp_name + " has failed");
+ return null;
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/test/MockBundle.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/test/MockBundle.java
new file mode 100644
index 0000000..d089dff
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/test/MockBundle.java
@@ -0,0 +1,190 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.cert.X509Certificate;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.*;
+
+public class MockBundle implements Bundle {
+
+ private final ClassLoader m_classloader;
+
+ /**
+ * @param cl the Classloader to load classes and resources.
+ */
+ public MockBundle(ClassLoader cl) {
+ m_classloader = cl;
+ }
+
+ public int getState() {
+ return 0;
+ }
+
+ public void start(int i) throws BundleException {
+ }
+
+ public void start() throws BundleException {
+ }
+
+ public void stop(int i) throws BundleException {
+ }
+
+ public void stop() throws BundleException {
+ }
+
+ public void update() throws BundleException {
+ }
+
+ public void update(InputStream in) throws BundleException {
+ }
+
+ public void uninstall() throws BundleException {
+ }
+
+ public Dictionary getHeaders() {
+ return null;
+ }
+
+ public long getBundleId() {
+ return 1; // 0 is the system bundle
+ }
+
+ public String getLocation() {
+ return null;
+ }
+
+ public ServiceReference[] getRegisteredServices() {
+ return null;
+ }
+
+ public ServiceReference[] getServicesInUse() {
+ return null;
+ }
+
+ public boolean hasPermission(Object permission) {
+ return false;
+ }
+
+ public URL getResource(String name) {
+ return m_classloader.getResource(name);
+ }
+
+ public Dictionary getHeaders(String locale) {
+ return null;
+ }
+
+ public String getSymbolicName() {
+ return null;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException {
+ return m_classloader.loadClass(name);
+ }
+
+ public Enumeration getResources(String name) throws IOException {
+ return m_classloader.getResources(name);
+ }
+
+ public Enumeration getEntryPaths(String path) {
+ return null;
+ }
+
+ public URL getEntry(String name) {
+ return null;
+ }
+
+ public long getLastModified() {
+ return 0;
+ }
+
+ public Enumeration findEntries(String path, String filePattern,
+ boolean recurse) {
+ return null;
+ }
+
+ public BundleContext getBundleContext() {
+ return null;
+ }
+
+ public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(int i) {
+ return null;
+ }
+
+ public Version getVersion() {
+ return null;
+ }
+
+ public <A> A adapt(Class<A> aClass) {
+ return null;
+ }
+
+ public File getDataFile(String s) {
+ return null;
+ }
+
+ /**
+ * Compares this object with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.
+ * <p/>
+ * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
+ * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This
+ * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
+ * <tt>y.compareTo(x)</tt> throws an exception.)
+ * <p/>
+ * <p>The implementor must also ensure that the relation is transitive:
+ * <tt>(x.compareTo(y)>0 && y.compareTo(z)>0)</tt> implies
+ * <tt>x.compareTo(z)>0</tt>.
+ * <p/>
+ * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
+ * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
+ * all <tt>z</tt>.
+ * <p/>
+ * <p>It is strongly recommended, but <i>not</i> strictly required that
+ * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>. Generally speaking, any
+ * class that implements the <tt>Comparable</tt> interface and violates
+ * this condition should clearly indicate this fact. The recommended
+ * language is "Note: this class has a natural ordering that is
+ * inconsistent with equals."
+ * <p/>
+ * <p>In the foregoing description, the notation
+ * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+ * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+ * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+ * <i>expression</i> is negative, zero or positive.
+ *
+ * @param o the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ * @throws ClassCastException if the specified object's type prevents it
+ * from being compared to this object.
+ */
+ public int compareTo(Bundle o) {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ContextSourceManagerTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ContextSourceManagerTest.java
new file mode 100644
index 0000000..3f6a69d
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ContextSourceManagerTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+
+import java.util.Hashtable;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Checks the behavior of the context source manager.
+ */
+public class ContextSourceManagerTest {
+
+ @Test
+ public void testSubstitute() throws Exception {
+ String filter_with_one_var = "(id=${id})";
+ String filter_with_two_vars = "(&(id=${id})(count=${system.count}))";
+
+ Hashtable<String, Object> context = new Hashtable<String, Object>();
+ context.put("id", "my.id");
+ context.put("system.count", 1);
+
+ String filter = ContextSourceManager.substitute(filter_with_one_var, context);
+ assertThat(filter).isEqualTo("(id=my.id)");
+
+ filter = ContextSourceManager.substitute(filter_with_two_vars, context);
+ assertThat(filter).isEqualTo("(&(id=my.id)(count=1))");
+ }
+
+ @Test
+ public void testEmptySubstitution() {
+ String filter_with_two_vars = "(&(id=${id})(count=${system.count}))";
+ Hashtable<String, Object> context = new Hashtable<String, Object>();
+ String filter = ContextSourceManager.substitute(filter_with_two_vars, context);
+ assertThat(filter).isEqualTo(filter_with_two_vars);
+ }
+
+ @Test
+ public void testTwoStepsSubstitution() {
+ String filter_with_vars_equality = "(${attr}=${var})";
+
+ Hashtable<String, Object> context1 = new Hashtable<String, Object>();
+ context1.put("var", "value");
+
+ Hashtable<String, Object> context2 = new Hashtable<String, Object>();
+ context2.put("attr", "prop");
+
+ String filter = ContextSourceManager.substitute(filter_with_vars_equality, context1);
+ assertThat(filter).isEqualTo("(${attr}=value)");
+
+ filter = ContextSourceManager.substitute(filter, context2);
+ assertThat(filter).isEqualTo("(prop=value)");
+ }
+
+ @Test
+ public void testExtractVariablesFromFilter() throws Exception {
+ String filter_with_one_var = "(id=${id})";
+ String filter_with_two_vars = "(&(id=${id})(count=${system.count}))";
+ String filter_with_vars_equality = "(${attr}=${var})";
+
+ assertThat(ContextSourceManager.extractVariablesFromFilter(filter_with_one_var)).containsExactly("id");
+ assertThat(ContextSourceManager.extractVariablesFromFilter(filter_with_two_vars)).contains("id",
+ "system.count");
+ assertThat(ContextSourceManager.extractVariablesFromFilter(filter_with_vars_equality)).contains("attr",
+ "var");
+ }
+
+ @Test
+ public void testBrokenFilters() throws Exception {
+ String broken = "(id=${i)";
+ try {
+ ContextSourceManager.extractVariablesFromFilter(broken);
+ fail("Unfinished variable undetected");
+ } catch (InvalidSyntaxException e) {
+ // OK
+ }
+
+ String broken2 = "(id=${})";
+ try {
+ ContextSourceManager.extractVariablesFromFilter(broken2);
+ fail("Empty variable undetected");
+ } catch (InvalidSyntaxException e) {
+ // OK
+ }
+
+ String broken3 = "(id=${I contain a space})";
+ try {
+ ContextSourceManager.extractVariablesFromFilter(broken3);
+ fail("Spaced variable undetected");
+ } catch (InvalidSyntaxException e) {
+ // OK
+ }
+ }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/InstanceConfigurationSourceTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/InstanceConfigurationSourceTest.java
new file mode 100644
index 0000000..ab5f436
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/InstanceConfigurationSourceTest.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.apache.felix.ipojo.ContextListener;
+import org.apache.felix.ipojo.ContextSource;
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the instance configuration context source.
+ */
+public class InstanceConfigurationSourceTest {
+
+ @Test
+ public void getProperties() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", 1);
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+ assertEquals(cs.getContext().get("prop1"), "value");
+ assertEquals(cs.getContext().get("prop2"), 1);
+ }
+
+ @Test
+ public void getProperty() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", 1);
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+ assertEquals(cs.getProperty("prop1"), "value");
+ assertEquals(cs.getProperty("prop2"), 1);
+ }
+
+ @Test
+ public void getMissingProperty() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", 1);
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+ assertNull(cs.getProperty("__property"));
+ }
+
+ @Test
+ public void emptyConfiguration() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+ assertNull(cs.getProperty("__property"));
+ }
+
+ @Test
+ public void addPropertyOnConfiguration() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+
+ SpyContextListener spy = new SpyContextListener();
+ cs.registerContextListener(spy, null);
+
+ Dictionary<String, Object> newConfiguration = new Hashtable<String, Object>();
+ newConfiguration.put("prop1", "value");
+ newConfiguration.put("prop2", "value2");
+
+ cs.reconfigure(newConfiguration);
+
+ assertEquals(spy.variables.size(), 1);
+ assertEquals(spy.variables.get("prop2"), "value2");
+ }
+
+ @Test
+ public void removePropertyOnConfiguration() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", "value2");
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+
+ SpyContextListener spy = new SpyContextListener();
+ cs.registerContextListener(spy, null);
+
+ Dictionary<String, Object> newConfiguration = new Hashtable<String, Object>();
+ newConfiguration.put("prop1", "value");
+
+ cs.reconfigure(newConfiguration);
+
+ assertEquals(spy.variables.size(), 1);
+ assertTrue(spy.variables.containsKey("prop2"));
+ assertEquals(spy.variables.get("prop2"), null);
+ }
+
+ @Test
+ public void updatePropertyOnConfiguration() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", "value2");
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+
+ SpyContextListener spy = new SpyContextListener();
+ cs.registerContextListener(spy, null);
+
+ Dictionary<String, Object> newConfiguration = new Hashtable<String, Object>();
+ newConfiguration.put("prop1", "new value");
+ newConfiguration.put("prop2", "value2");
+
+ cs.reconfigure(newConfiguration);
+
+ assertEquals(spy.variables.size(), 1);
+ assertEquals(spy.variables.get("prop1"), "new value");
+ }
+
+ @Test
+ public void add_remove_update() {
+ Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+ configuration.put("prop1", "value");
+ configuration.put("prop2", "value2");
+ InstanceConfigurationSource cs = new InstanceConfigurationSource(configuration);
+
+ SpyContextListener spy = new SpyContextListener();
+ cs.registerContextListener(spy, null);
+
+ Dictionary<String, Object> newConfiguration = new Hashtable<String, Object>();
+ newConfiguration.put("prop1", "new value");
+ newConfiguration.put("prop3", "value3");
+
+ cs.reconfigure(newConfiguration);
+
+ assertEquals(spy.variables.size(), 3);
+ assertEquals(spy.variables.get("prop1"), "new value");
+ assertEquals(spy.variables.get("prop3"), "value3");
+ assertEquals(spy.variables.get("prop2"), null);
+
+ }
+
+ private class SpyContextListener implements ContextListener {
+
+ Map<String, Object> variables = new HashMap<String, Object>();
+
+ public void update(ContextSource source, String property, Object value) {
+ variables.put(property, value);
+ }
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ManifestMetadataParserTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ManifestMetadataParserTest.java
new file mode 100644
index 0000000..eaaae70
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/ManifestMetadataParserTest.java
@@ -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.felix.ipojo.util;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+
+/**
+ * Test the {@link ManifestMetadataParser}
+ */
+public class ManifestMetadataParserTest extends TestCase {
+
+ /**
+ * Test FELIX-2685.
+ * The element name contains ':' as in:
+ * "//jasmine.ow2.org/rules/1.0.0:configuration"
+ * @throws ParseException
+ */
+ public void testNameWithColumn() throws ParseException {
+ // Create a test element
+ String header = "http://jasmine.ow2.org/rules/1.0.0:configuration {}";
+ Element elem = ManifestMetadataParser.parse(header);
+
+ Assert.assertEquals("http://jasmine.ow2.org/rules/1.0.0", elem.getNameSpace());
+ Assert.assertEquals("configuration", elem.getName());
+ }
+
+ /**
+ * Check the parsing of handler element using {@link ManifestMetadataParser#parseHeader(String)}
+ * @throws ParseException
+ */
+ public void testHandlerHeader() throws ParseException {
+ String header = "handler { $name=\"wbp\" $classname=\"org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler\"" +
+ " $namespace=\"org.apache.felix.ipojo.whiteboard\" manipulation { $super=\"org.apache.felix.ipojo.PrimitiveHandler\"" +
+ " field { $name=\"m_managers\" $type=\"java.util.List\" }method { $name=\"$init\" }method { $arguments=" +
+ "\"{org.apache.felix.ipojo.metadata.Element,java.util.Dictionary}\" $name=\"configure\" }method { $name=\"start\"" +
+ " }method { $arguments=\"{int}\" $name=\"stateChanged\" }method { $name=\"stop\" }}}";
+
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.parseHeader(header);
+
+ Element[] elems = parser.getComponentsMetadata();
+ Assert.assertEquals(1, elems.length);
+
+ Element element = elems[0];
+ Assert.assertEquals("handler", element.getName());
+ Assert.assertNull(element.getNameSpace());
+
+ Assert.assertEquals("wbp", element.getAttribute("name"));
+ Assert.assertEquals("org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler", element.getAttribute("classname"));
+ Assert.assertEquals("org.apache.felix.ipojo.whiteboard", element.getAttribute("namespace"));
+
+ // Check the manipulation element
+ Element[] manip = element.getElements("manipulation");
+ Assert.assertNotNull(manip[0]);
+
+ Element[] methods = manip[0].getElements("method");
+ Assert.assertEquals(5, methods.length);
+ }
+
+ /**
+ * Check the parsing of handler element using {@link ManifestMetadataParser#parseHeaderMetadata(String)}
+ * @throws ParseException
+ */
+ public void testHandlerHeader2() throws ParseException {
+ String header = "handler { $name=\"wbp\" $classname=\"org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler\"" +
+ " $namespace=\"org.apache.felix.ipojo.whiteboard\" manipulation { $super=\"org.apache.felix.ipojo.PrimitiveHandler\"" +
+ " field { $name=\"m_managers\" $type=\"java.util.List\" }method { $name=\"$init\" }method { $arguments=" +
+ "\"{org.apache.felix.ipojo.metadata.Element,java.util.Dictionary}\" $name=\"configure\" }method { $name=\"start\"" +
+ " }method { $arguments=\"{int}\" $name=\"stateChanged\" }method { $name=\"stop\" }}}";
+
+ // This method returns an iPOJO root element
+ Element elem = ManifestMetadataParser.parseHeaderMetadata(header);
+ Element element = elem.getElements("handler")[0];
+
+ Assert.assertEquals("handler", element.getName());
+ Assert.assertNull(element.getNameSpace());
+
+ Assert.assertEquals("wbp", element.getAttribute("name"));
+ Assert.assertEquals("org.apache.felix.ipojo.handler.wbp.WhiteBoardPatternHandler", element.getAttribute("classname"));
+ Assert.assertEquals("org.apache.felix.ipojo.whiteboard", element.getAttribute("namespace"));
+
+ // Check the manipulation element
+ Element[] manip = element.getElements("manipulation");
+ Assert.assertNotNull(manip[0]);
+
+ Element[] methods = manip[0].getElements("method");
+ Assert.assertEquals(5, methods.length);
+ }
+
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/SystemPropertiesSourceTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/SystemPropertiesSourceTest.java
new file mode 100644
index 0000000..1141b03
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/util/SystemPropertiesSourceTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.util;
+
+import org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Test the system property context source.
+ */
+public class SystemPropertiesSourceTest {
+
+ @After
+ public void tearDown() {
+ System.clearProperty("__property");
+ }
+
+ @Test
+ public void getProperties() {
+ System.setProperty("__property", "__value");
+ SystemPropertiesSource cs = new SystemPropertiesSource();
+ assertEquals(cs.getContext().get("__property"), "__value");
+ }
+
+ @Test
+ public void getProperty() {
+ System.setProperty("__property", "__value");
+ SystemPropertiesSource cs = new SystemPropertiesSource();
+ assertEquals(cs.getProperty("__property"), "__value");
+ }
+
+ @Test
+ public void getMissingProperty() {
+ SystemPropertiesSource cs = new SystemPropertiesSource();
+ assertNull(cs.getProperty("__property"));
+ }
+}
diff --git a/ipojo/runtime/core/src/test/resources/manipulation/MANIFEST.MF b/ipojo/runtime/core/src/test/resources/manipulation/MANIFEST.MF
new file mode 100644
index 0000000..4becd87
--- /dev/null
+++ b/ipojo/runtime/core/src/test/resources/manipulation/MANIFEST.MF
@@ -0,0 +1,142 @@
+Manifest-Version: 1.0
+Export-Package: org.apache.felix.ipojo.test.scenarios.manipulation.ser
+ vice
+iPOJO-Components: component { $name="ManipulationMetadata-FooProviderT
+ ype-1" $classname="org.apache.felix.ipojo.test.scenarios.component.Fo
+ oProviderType1" $architecture="true" provides { }manipulation { field
+ { $name="m_context" $type="org.osgi.framework.BundleContext" }field
+ { $name="m_foo" $type="java.lang.String" }field { $name="m_bar" $type
+ ="int" }method { $arguments="{org.osgi.framework.BundleContext}" $nam
+ e="singleton" $return="org.apache.felix.ipojo.test.scenarios.componen
+ t.FooProviderType1" }method { $arguments="{org.osgi.framework.BundleC
+ ontext}" $name="several" $return="org.apache.felix.ipojo.test.scenari
+ os.component.FooProviderType1" }method { $arguments="{org.osgi.framew
+ ork.BundleContext}" $name="$init" }method { $name="foo" $return="bool
+ ean" }method { $name="fooProps" $return="java.util.Properties" }metho
+ d { $name="testException" }method { $name="testTry" }method { $argume
+ nts="{java.lang.String}" $name="testTry2" }method { $arguments="{java
+ .lang.String}" $name="nexttry" }method { $name="getBoolean" $return="
+ boolean" }method { $name="getDouble" $return="double" }method { $name
+ ="getInt" $return="int" }method { $name="getLong" $return="long" }met
+ hod { $name="getObject" $return="java.lang.Boolean" }method { $argume
+ nts="{int,java.lang.String,org.osgi.framework.BundleContext}" $name="
+ $init" }interface { $name="org.apache.felix.ipojo.test.scenarios.mani
+ pulation.service.FooService" }}}component { $name="ManipulationMetada
+ ta-FooBarProviderType-1" $classname="org.apache.felix.ipojo.test.scen
+ arios.component.FooBarProviderType1" $architecture="true" provides {
+ }manipulation { method { $name="$init" }method { $name="foo" $return=
+ "boolean" }method { $name="fooProps" $return="java.util.Properties" }
+ method { $name="bar" $return="boolean" }method { $name="getProps" $re
+ turn="java.util.Properties" }method { $name="getBoolean" $return="boo
+ lean" }method { $name="getDouble" $return="double" }method { $name="g
+ etInt" $return="int" }method { $name="getLong" $return="long" }method
+ { $name="getObject" $return="java.lang.Boolean" }interface { $name="
+ org.apache.felix.ipojo.test.scenarios.manipulation.service.FooService
+ " }interface { $name="org.apache.felix.ipojo.test.scenarios.manipulat
+ ion.service.BarService" }}}component { $name="ManipulationMetadata-Fo
+ oProviderType-Dyn" $classname="org.apache.felix.ipojo.test.scenarios.
+ component.FooProviderTypeDyn" $architecture="true" provides { propert
+ y { $field="intProp" $mandatory="false" $name="int" $value="2" }prope
+ rty { $field="boolProp" $mandatory="false" $name="boolean" $value="fa
+ lse" }property { $field="strProp" $mandatory="false" $name="string" $
+ value="foo" }property { $field="strAProp" $mandatory="false" $name="s
+ trAProp" $value="[foo, bar]" }property { $field="intAProp" $mandatory
+ ="false" $name="intAProp" $value="[ 1,2,3]" }}manipulation { field {
+ $name="boolProp" $type="boolean" }field { $name="strProp" $type="java
+ .lang.String" }field { $name="strAProp" $type="java.lang.String[]" }f
+ ield { $name="intProp" $type="int" }field { $name="intAProp" $type="i
+ nt[]" }method { $name="$init" }method { $name="foo" $return="boolean"
+ }method { $name="fooProps" $return="java.util.Properties" }method {
+ $name="getBoolean" $return="boolean" }method { $name="getDouble" $ret
+ urn="double" }method { $name="getInt" $return="int" }method { $name="
+ getLong" $return="long" }method { $name="getObject" $return="java.lan
+ g.Boolean" }interface { $name="org.apache.felix.ipojo.test.scenarios.
+ manipulation.service.FooService" }}}component { $name="ManipulationMe
+ tadata-PrimitiveManipulationTester" $classname="org.apache.felix.ipoj
+ o.test.scenarios.component.Manipulation23Tester" $architecture="true"
+ provides { }manipulation { field { $name="f" $type="float" }field {
+ $name="d" $type="double" }field { $name="is" $type="int[]" }field { $
+ name="bools" $type="boolean[]" }field { $name="b" $type="byte" }field
+ { $name="ls" $type="long[]" }field { $name="c" $type="char" }field {
+ $name="l" $type="long" }field { $name="bs" $type="byte[]" }field { $
+ name="cs" $type="char[]" }field { $name="i" $type="int" }field { $nam
+ e="s" $type="short" }field { $name="fs" $type="float[]" }field { $nam
+ e="ss" $type="short[]" }field { $name="bool" $type="boolean" }field {
+ $name="ds" $type="double[]" }method { $name="$init" }method { $name=
+ "getBoolean" $return="boolean" }method { $name="getBooleans" $return=
+ "boolean[]" }method { $name="getByte" $return="byte" }method { $name=
+ "getBytes" $return="byte[]" }method { $name="getChar" $return="char"
+ }method { $name="getChars" $return="char[]" }method { $name="getDoubl
+ e" $return="double" }method { $name="getDoubles" $return="double[]" }
+ method { $name="getFloat" $return="float" }method { $name="getFloats"
+ $return="float[]" }method { $name="getInt" $return="int" }method { $
+ name="getInts" $return="int[]" }method { $name="getLong" $return="lon
+ g" }method { $name="getLongs" $return="long[]" }method { $name="getSh
+ ort" $return="short" }method { $name="getShorts" $return="short[]" }m
+ ethod { $arguments="{boolean}" $name="setBoolean" }method { $argument
+ s="{boolean[]}" $name="setBooleans" }method { $arguments="{byte}" $na
+ me="setByte" }method { $arguments="{byte[]}" $name="setBytes" }method
+ { $arguments="{char}" $name="setChar" }method { $arguments="{char[]}
+ " $name="setChars" }method { $arguments="{double}" $name="setDouble"
+ }method { $arguments="{double[]}" $name="setDoubles" }method { $argum
+ ents="{float}" $name="setFloat" }method { $arguments="{float[]}" $nam
+ e="setFloats" }method { $arguments="{int}" $name="setInt" }method { $
+ arguments="{int[]}" $name="setInts" }method { $arguments="{long}" $na
+ me="setLong" }method { $arguments="{long[]}" $name="setLongs" }method
+ { $arguments="{short}" $name="setShort" }method { $arguments="{short
+ []}" $name="setShorts" }method { $arguments="{long,java.lang.String}"
+ $name="setLong" }interface { $name="org.apache.felix.ipojo.test.scen
+ arios.manipulation.service.PrimitiveManipulationTestService" }}}compo
+ nent { $name="ManipulationMetadata-SimpleMultipleCheckServiceProvider
+ " $classname="org.apache.felix.ipojo.test.scenarios.component.Multipl
+ eCheckService" $architecture="true" provides { }manipulation { field
+ { $name="refU" $type="int" }field { $name="objectU" $type="int" }fiel
+ d { $name="bothB" $type="int" }field { $name="objectB" $type="int" }f
+ ield { $name="bothU" $type="int" }field { $name="fs" $type="org.apach
+ e.felix.ipojo.test.scenarios.manipulation.service.FooService[]" }fiel
+ d { $name="simpleU" $type="int" }field { $name="simpleB" $type="int"
+ }field { $name="refB" $type="int" }method { $name="$init" }method { $
+ name="check" $return="boolean" }method { $name="getBoolean" $return="
+ boolean" }method { $name="getInt" $return="int" }method { $name="getL
+ ong" $return="long" }method { $name="getDouble" $return="double" }met
+ hod { $arguments="{java.lang.Object,java.lang.String}" $name="doNothi
+ ng" $return="java.lang.Object" }method { $name="getProps" $return="ja
+ va.util.Properties" }method { $name="voidBind" }method { $name="voidU
+ nbind" }method { $arguments="{org.apache.felix.ipojo.test.scenarios.m
+ anipulation.service.FooService}" $name="objectBind" }method { $argume
+ nts="{org.apache.felix.ipojo.test.scenarios.manipulation.service.FooS
+ ervice}" $name="objectUnbind" }method { $arguments="{org.osgi.framewo
+ rk.ServiceReference}" $name="refBind" }method { $arguments="{org.osgi
+ .framework.ServiceReference}" $name="refUnbind" }method { $arguments=
+ "{org.apache.felix.ipojo.test.scenarios.manipulation.service.FooServi
+ ce,org.osgi.framework.ServiceReference}" $name="bothBind" }method { $
+ arguments="{org.apache.felix.ipojo.test.scenarios.manipulation.servic
+ e.FooService,org.osgi.framework.ServiceReference}" $name="bothUnbind"
+ }interface { $name="org.apache.felix.ipojo.test.scenarios.manipulati
+ on.service.CheckService" }}requires { $field="fs" }}component { $clas
+ sname="org.apache.felix.ipojo.test.scenarios.component.Child" manipul
+ ation { $super="org.apache.felix.ipojo.test.scenarios.component.Paren
+ t" method { $arguments="{java.lang.String}" $name="$init" }}}componen
+ t { $classname="org.apache.felix.ipojo.test.scenarios.component.Multi
+ constructor" manipulation { method { $arguments="{java.lang.String,ja
+ va.lang.String}" $name="$init" }method { $arguments="{java.lang.Strin
+ g,int}" $name="$init" }method { $arguments="{java.lang.String,java.la
+ ng.String,int}" $name="$init" }}}
+Test-Suite: org.apache.felix.ipojo.test.scenarios.manipulation.Manipul
+ ationTestSuite
+Built-By: clement
+Tool: Bnd-0.0.357
+Bundle-Name: iPOJO Manipulation Metadata Test Suite
+Created-By: Apache Maven Bundle Plugin & iPOJO 1.6.0
+Build-Jdk: 1.6.0_22
+Bundle-Version: 1.5.0.SNAPSHOT
+Bnd-LastModified: 1292762858403
+Bundle-ManifestVersion: 2
+Import-Package: org.osgi.service.log;version=1.3, org.apache.felix.ipo
+ jo.test.scenarios.manipulation.service, org.apache.felix.ipojo.junit4
+ osgi, junit.framework, org.apache.felix.ipojo.architecture;version=1.
+ 6, org.apache.felix.ipojo;version=1.6, org.osgi.framework;version=1.5
+ , org.osgi.service.cm;version=1.2, org.apache.felix.ipojo.metadata, o
+ rg.apache.felix.ipojo.parser;version=1.6
+Bundle-SymbolicName: tests.manipulation.metadata
+
diff --git a/ipojo/runtime/distributions/maven-tutorial/pom.xml b/ipojo/runtime/distributions/maven-tutorial/pom.xml
new file mode 100644
index 0000000..9292ace
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+
+
+ <packaging>pom</packaging>
+
+ <name>Apache Felix iPOJO - Distribution - Maven Tutorial</name>
+ <artifactId>org.apache.felix.ipojo.distribution.maventutorial</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+
+ <description>This project builds the iPOJO Maven tutorial package</description>
+
+
+ <build>
+ <plugins>
+ <!--
+ The build is configured to filter the skeleton and generate a distribution out of it.
+ -->
+
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <phase>compile</phase>
+ <id>copy-skeleton</id>
+ <configuration>
+ <outputDirectory>${project.build.directory}/maven-tutorial</outputDirectory>
+ <delimiters>
+ <!-- we use a specific delimiter to avoid filtering internal properties -->
+ <delimiter>@</delimiter>
+ </delimiters>
+ <escapeString>\</escapeString>
+ <resources>
+ <resource>
+ <directory>src/main/skeleton</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <attach>true</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <id>build-distribution</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/distribution.xml</descriptor>
+ </descriptors>
+
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..f02b82d
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,27 @@
+
+I. Included Third-Party Software
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://kxml.sourceforge.net.
+Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany.
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The Codehaus (http://www.codehaus.org)
+Licensed under the Apache License 2.0.
+
+III. License Summary
+
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..727b0df
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,8 @@
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://kxml.sourceforge.net.
+Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany.
+Licensed under BSD License.
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/assembly/distribution.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/assembly/distribution.xml
new file mode 100644
index 0000000..8f2d4c3
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/assembly/distribution.xml
@@ -0,0 +1,45 @@
+<!--
+ ~ 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>distribution</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/maven-shared-archive-resources/META-INF</directory>
+ <outputDirectory/>
+ </fileSet>
+
+ <fileSet>
+ <directory>${project.build.directory}/maven-tutorial</directory>
+ <outputDirectory/>
+ </fileSet>
+ </fileSets>
+
+
+</assembly>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/pom.xml
new file mode 100644
index 0000000..d383ed6
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <packaging>bundle</packaging>
+
+ <artifactId>hello.client.annotations</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ ipojo.example.hello.client
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/HelloClient.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/HelloClient.java
new file mode 100644
index 0000000..32a339a
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/HelloClient.java
@@ -0,0 +1,88 @@
+/*
+ * 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 ipojo.example.hello.client;
+
+import ipojo.example.hello.Hello;
+import org.apache.felix.ipojo.annotations.*;
+
+/**
+ * A simple Hello service client. This client use annotation instead of XML metadata.
+ * If no Hello provider are available, it uses a default implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component(name = "AnnotatedHelloClient")
+@Instantiate
+public class HelloClient implements Runnable {
+
+ /**
+ * Delay between two invocations.
+ */
+ private static final int DELAY = 10000;
+ /**
+ * Hello services. Injected by the container.
+ */
+ @Requires(optional = true, defaultimplementation = MyDummyHello.class)
+ private Hello hello;
+ /**
+ * End flag.
+ */
+ private boolean m_end;
+
+ /**
+ * Run method.
+ *
+ * @see Runnable#run()
+ */
+ public void run() {
+ while (!m_end) {
+ try {
+ invokeHelloServices();
+ Thread.sleep(DELAY);
+ } catch (InterruptedException ie) {
+ /* will recheck end */
+ }
+ }
+ }
+
+ /**
+ * Invoke hello services.
+ */
+ public void invokeHelloServices() {
+ System.out.println(hello.sayHello("iPOJO "));
+ }
+
+ /**
+ * Starting.
+ */
+ @Validate
+ public void starting() {
+ Thread thread = new Thread(this);
+ m_end = false;
+ thread.start();
+ }
+
+ /**
+ * Stopping.
+ */
+ @Invalidate
+ public void stopping() {
+ m_end = true;
+ }
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/MyDummyHello.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/MyDummyHello.java
new file mode 100644
index 0000000..cc72fb5
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.client.annotations/src/main/java/ipojo/example/hello/client/MyDummyHello.java
@@ -0,0 +1,30 @@
+/*
+ * 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 ipojo.example.hello.client;
+
+import ipojo.example.hello.Hello;
+
+public class MyDummyHello implements Hello {
+
+ public String sayHello(String name) {
+ return "Bonjour, I'm the default-implementation";
+ }
+
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.felix.annotations/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.felix.annotations/pom.xml
new file mode 100644
index 0000000..f5eef4e
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.felix.annotations/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hello.felix.annotations</artifactId>
+
+ <description>A project building a Felix with the annotated Hello service and client</description>
+
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <!-- our project -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.impl.annotations</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.client.annotations</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+
+ <execution>
+ <id>unpack-felix</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>org.apache.felix.ipojo.distribution.quickstart</includeArtifactIds>
+ <outputDirectory>\${project.build.directory}/tmp</outputDirectory>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>copy-bundles</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ hello.service,
+ hello.impl.annotations,
+ hello.client.annotations
+ </includeArtifactIds>
+ <outputDirectory>\${project.build.directory}/bundle</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <phase>compile</phase>
+ <id>copy-distribution</id>
+ <configuration>
+ <outputDirectory>\${project.build.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>\${project.build.directory}/tmp/ipojo-distribution-\${project.version}</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/pom.xml
new file mode 100644
index 0000000..cbc6c37
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hello.impl.annotations</artifactId>
+
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ ipojo.example.hello.impl
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/src/main/java/ipojo/example/hello/impl/HelloImpl.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/src/main/java/ipojo/example/hello/impl/HelloImpl.java
new file mode 100644
index 0000000..9818f81
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/annotations/hello.impl.annotations/src/main/java/ipojo/example/hello/impl/HelloImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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 ipojo.example.hello.impl;
+
+import ipojo.example.hello.Hello;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+
+/**
+ * Component implementing the Hello service.
+ * This class used annotations to describe the component type.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component
+@Provides
+@Instantiate // Declare an instance of the component
+public class HelloImpl implements Hello {
+
+
+ @ServiceProperty
+ public String boo = "boo";
+
+ @ServiceProperty
+ public String bla = "bla";
+
+
+ /**
+ * Returns an 'Hello' message.
+ * @param name : name
+ * @return Hello message
+ * @see ipojo.example.hello.Hello#sayHello(String)
+ */
+ public String sayHello(String name) { return "hello " + name + "."; }
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/pom.xml
new file mode 100644
index 0000000..6e84e87
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/pom.xml
@@ -0,0 +1,48 @@
+<!--
+ ~ 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>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ </parent>
+
+ <packaging>bundle</packaging>
+
+ <artifactId>hello.service</artifactId>
+ <name>Hello Service</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ ipojo.example.hello
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/src/main/java/ipojo/example/hello/Hello.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/src/main/java/ipojo/example/hello/Hello.java
new file mode 100644
index 0000000..e0c25da
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/hello.service/src/main/java/ipojo/example/hello/Hello.java
@@ -0,0 +1,33 @@
+/*
+ * 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 ipojo.example.hello;
+
+/**
+ * Hello Interface.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Hello {
+
+ /**
+ * Returns a message like: "Hello $user_name".
+ * @param name the name
+ * @return the hello message
+ */
+ String sayHello(String name);
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/pom.xml
new file mode 100644
index 0000000..9884587
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+
+ <packaging>pom</packaging>
+
+ <description>
+ The iPOJO Maven tutorial
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.distribution.quickstart</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <modules>
+ <module>hello.service</module>
+
+ <!-- XML -->
+ <module>xml/hello.impl.xml</module>
+ <module>xml/hello.client.xml</module>
+ <module>xml/hello.felix.xml</module>
+
+ <!-- Annotation -->
+ <module>annotations/hello.impl.annotations</module>
+ <module>annotations/hello.client.annotations</module>
+ <module>annotations/hello.felix.annotations</module>
+ </modules>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>${project.version}</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/pom.xml
new file mode 100644
index 0000000..3a8c114
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <packaging>bundle</packaging>
+
+ <artifactId>hello.client.xml</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ ipojo.example.hello.client
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/java/ipojo/example/hello/client/HelloClient.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/java/ipojo/example/hello/client/HelloClient.java
new file mode 100644
index 0000000..85e2ff5
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/java/ipojo/example/hello/client/HelloClient.java
@@ -0,0 +1,90 @@
+/*
+ * 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 ipojo.example.hello.client;
+
+import ipojo.example.hello.Hello;
+
+/**
+ * Hello Service simple client.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HelloClient implements Runnable {
+
+ /**
+ * Delay between two invocations.
+ */
+ private static final int DELAY = 10000;
+
+ /**
+ * Hello services.
+ * Injected by the container.
+ * */
+ private Hello[] hellos; // Service dependency
+
+ /**
+ * End flag.
+ * */
+ private boolean end;
+
+ /**
+ * Name property.
+ * Injected by the container.
+ * */
+ private String name;
+
+ /**
+ * Run method.
+ * @see Runnable#run()
+ */
+ public void run() {
+ while (!end) {
+ try {
+ invokeHelloServices();
+ Thread.sleep(DELAY);
+ } catch (InterruptedException ie) {
+ /* will recheck end */
+ }
+ }
+ }
+
+ /**
+ * Invoke hello services.
+ */
+ public void invokeHelloServices() {
+ for (Hello hello : hellos) {
+ System.out.println(hello.sayHello(name));
+ }
+ }
+
+ /**
+ * Starting.
+ */
+ public void starting() {
+ Thread thread = new Thread(this);
+ end = false;
+ thread.start();
+ }
+
+ /**
+ * Stopping.
+ */
+ public void stopping() {
+ end = true;
+ }
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/resources/metadata.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/resources/metadata.xml
new file mode 100644
index 0000000..e84d61b
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.client.xml/src/main/resources/metadata.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/CURRENT/core.xsd"
+ xmlns="org.apache.felix.ipojo">
+ <component classname="ipojo.example.hello.client.HelloClient"
+ architecture="true">
+ <!-- Declare the service dependency -->
+ <requires field="hellos" />
+
+ <!-- Lifecycle callbacks -->
+ <callback transition="validate" method="starting" />
+ <callback transition="invalidate" method="stopping" />
+
+ <!-- A simple property coming from the instance configuration -->
+ <properties>
+ <property field="name" name="name" />
+ </properties>
+ </component>
+
+ <!--
+ Declaration of an instance of the component specified above.
+ Notice the instance property 'name' setting the value of the component's property
+ -->
+ <instance component="ipojo.example.hello.client.HelloClient">
+ <property name="name" value="iPOJO" />
+ </instance>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.felix.xml/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.felix.xml/pom.xml
new file mode 100644
index 0000000..1f1d523
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.felix.xml/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hello.felix.xml</artifactId>
+
+ <description>A project building a Felix with the XML Hello service and client</description>
+
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <!-- our project -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.impl.xml</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.client.xml</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+
+ <execution>
+ <id>unpack-felix</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>org.apache.felix.ipojo.distribution.quickstart</includeArtifactIds>
+ <outputDirectory>\${project.build.directory}/tmp</outputDirectory>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>copy-bundles</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ hello.service,
+ hello.impl.xml,
+ hello.client.xml,
+ org.apache.felix.log
+ </includeArtifactIds>
+ <outputDirectory>\${project.build.directory}/bundle</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <phase>compile</phase>
+ <id>copy-distribution</id>
+ <configuration>
+ <outputDirectory>\${project.build.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>\${project.build.directory}/tmp/ipojo-distribution-\${project.version}</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/pom.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/pom.xml
new file mode 100644
index 0000000..371cb69
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>ipojo-maven-tutorial</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hello.impl.xml</artifactId>
+
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>hello.service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ ipojo.example.hello.impl
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/java/ipojo/example/hello/impl/HelloImpl.java b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/java/ipojo/example/hello/impl/HelloImpl.java
new file mode 100644
index 0000000..6fd36e3
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/java/ipojo/example/hello/impl/HelloImpl.java
@@ -0,0 +1,36 @@
+/*
+ * 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 ipojo.example.hello.impl;
+
+import ipojo.example.hello.Hello;
+
+/**
+ * Component implementing the Hello service.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HelloImpl implements Hello {
+
+ /**
+ * Returns an 'Hello' message.
+ * @param name : name
+ * @return Hello message
+ * @see ipojo.example.hello.Hello#sayHello(String)
+ */
+ public String sayHello(String name) { return "hello " + name; }
+}
diff --git a/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/resources/metadata.xml b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/resources/metadata.xml
new file mode 100644
index 0000000..26803d4
--- /dev/null
+++ b/ipojo/runtime/distributions/maven-tutorial/src/main/skeleton/xml/hello.impl.xml/src/main/resources/metadata.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ 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.
+ -->
+
+<ipojo>
+ <component className="ipojo.example.hello.impl.HelloImpl"
+ name="HelloProvider" architecture="true">
+ <provides />
+ </component>
+ <instance component="HelloProvider" name="HelloService" />
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/quickstart/pom.xml b/ipojo/runtime/distributions/quickstart/pom.xml
new file mode 100644
index 0000000..7ef2289
--- /dev/null
+++ b/ipojo/runtime/distributions/quickstart/pom.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+
+
+ <packaging>pom</packaging>
+
+ <name>Apache Felix iPOJO - Distribution - Quickstart</name>
+ <artifactId>org.apache.felix.ipojo.distribution.quickstart</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <properties>
+ <!-- Felix version -->
+ <felix.version>4.2.1</felix.version>
+
+ <!-- The location where the felix distribution is downloaded and expanded -->
+ <felix.destination>${project.build.directory}/felix-distribution</felix.destination>
+
+ <!-- The location where the legal files are generated -->
+ <legal.files>${project.build.directory}/maven-shared-archive-resources/META-INF</legal.files>
+
+ <!-- The base directory of the distribution -->
+ <distribution.baseDirectory>ipojo-distribution-${project.version}</distribution.baseDirectory>
+ </properties>
+
+ <description>
+ A distribution of Felix including iPOJO core and gogo commands
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.main.distribution</artifactId>
+ <version>${felix.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!--
+ The build is configured to download and unpack the felix distribution to the felix-distribution folder.
+ The assembly copy the unpacked file, stripping the base directory of the distribution
+ -->
+
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ <executions>
+ <execution>
+ <id>copy-felix-distribution</id>
+ <phase>package</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeGroupIds>org.apache.felix</includeGroupIds>
+ <includeTypes>zip</includeTypes>
+ <includeArtifactIds>org.apache.felix.main.distribution</includeArtifactIds>
+ <outputDirectory>${felix.destination}</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <attach>true</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <id>build-distribution</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/distribution.xml</descriptor>
+ </descriptors>
+
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>ianal-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>verify-legal-files</goal>
+ </goals>
+ <configuration>
+ <searchPaths>
+ <searchPath>${distribution.baseDirectory}</searchPath>
+ </searchPaths>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..f02b82d
--- /dev/null
+++ b/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,27 @@
+
+I. Included Third-Party Software
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://kxml.sourceforge.net.
+Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany.
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The Codehaus (http://www.codehaus.org)
+Licensed under the Apache License 2.0.
+
+III. License Summary
+
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..727b0df
--- /dev/null
+++ b/ipojo/runtime/distributions/quickstart/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,8 @@
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2012).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://kxml.sourceforge.net.
+Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany.
+Licensed under BSD License.
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/quickstart/src/main/assembly/distribution.xml b/ipojo/runtime/distributions/quickstart/src/main/assembly/distribution.xml
new file mode 100644
index 0000000..13fa2ba
--- /dev/null
+++ b/ipojo/runtime/distributions/quickstart/src/main/assembly/distribution.xml
@@ -0,0 +1,61 @@
+<!--
+ ~ 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>distribution</id>
+
+ <formats>
+ <format>dir</format>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>${distribution.baseDirectory}</baseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${felix.destination}/felix-framework-${felix.version}</directory>
+ <outputDirectory/>
+ <includes>
+ <include>bin/**</include>
+ <include>bundle/**</include>
+ <include>conf/**</include>
+ </includes>
+ </fileSet>
+
+ <fileSet>
+ <directory>${legal.files}</directory>
+ <outputDirectory/>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <includes>
+ <include>*:org.apache.felix.ipojo:*</include>
+ <include>*:org.apache.felix.ipojo.gogo:*</include>
+ </includes>
+ <unpack>false</unpack>
+ <outputDirectory>bundle</outputDirectory>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/pom.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/pom.xml
new file mode 100644
index 0000000..71d5809
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/pom.xml
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <packaging>pom</packaging>
+
+ <name>Apache Felix iPOJO - Distribution - 10 minutes tutorial</name>
+ <artifactId>org.apache.felix.ipojo.distribution.10mintutorial</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+
+ <description>This project builds the 10 minutes tutorial package</description>
+
+ <properties>
+ <ipojo.manipulator.version>1.12.1</ipojo.manipulator.version>
+ <bnd.version>1.50.0</bnd.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+
+ <execution>
+ <id>unpack-quickstart</id>
+ <phase>package</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>org.apache.felix.ipojo.distribution.quickstart</includeArtifactIds>
+ <outputDirectory>${project.build.directory}/dist</outputDirectory>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>copy-ant-tasks</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeArtifactIds>
+ org.apache.felix.ipojo.ant,
+ bnd
+ </includeArtifactIds>
+ <outputDirectory>${project.build.directory}/dist/tasks</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+
+ <dependencies>
+ </dependencies>
+ </plugin>
+
+ <!--
+ we also copy properties file to the distribution folder,
+ the properties are stored in src/main/resources/props
+ -->
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>copy-skeleton</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>
+ ${project.build.directory}/dist
+ </outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/skeleton</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <includeEmptyDirs>true</includeEmptyDirs>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-solution</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>
+ ${project.build.directory}/dist/solution
+ </outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/solution</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <includeEmptyDirs>true</includeEmptyDirs>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-legal</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>
+ ${project.build.directory}/dist/
+ </outputDirectory>
+ <resources>
+ <resource>
+ <directory>${project.build.directory}/maven-shared-archive-resources/META-INF</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ <includeEmptyDirs>true</includeEmptyDirs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <configuration>
+ <target>
+ <ant dir="target/dist" target="clean" />
+ <ant dir="target/dist" target="package" />
+ <ant dir="target/dist" target="dist" />
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ <version>1.7.0</version>
+ <scope>system</scope>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/dist/dist/tutorial.zip</file>
+ <type>zip</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>ianal-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>verify-legal-files</goal>
+ </goals>
+ <configuration>
+ <!-- as it's not possible to configure the plugin to check files contained in the root of
+ the zip file, we have to skip it -->
+ <skip>true</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.ant</artifactId>
+ <version>${ipojo.manipulator.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>biz.aQute</groupId>
+ <artifactId>bnd</artifactId>
+ <version>${bnd.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.distribution.quickstart</artifactId>
+ <version>${project.version}</version>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/build.xml
new file mode 100644
index 0000000..7eab9f0
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/build.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker.example" default="package" basedir=".">
+
+ <target name="clean">
+ <ant dir="spell.services" target="clean"/>
+ <ant dir="spell.english" target="clean"/>
+ <ant dir="spell.checker" target="clean"/>
+ <ant dir="spell.checker.gui" target="clean"/>
+ <ant dir="solution" target="clean"/>
+ <delete dir="ipojo-distribution-${project.version}/felix-cache"/>
+ <delete dir="dist"/>
+ </target>
+
+ <target name="package">
+ <ant dir="spell.services" target="package"/>
+ <ant dir="spell.english" target="package"/>
+ <ant dir="spell.checker" target="package"/>
+ <ant dir="spell.checker.gui" target="package"/>
+ <ant dir="solution" target="package"/>
+ </target>
+
+ <target name="dist" depends="clean">
+ <mkdir dir="dist"/>
+ <zip destfile="dist/tutorial.zip">
+ <fileset dir=".">
+ <exclude name="dist"/>
+ <exclude name=".*"/>
+ <exclude name="*/_*"/>
+ </fileset>
+ </zip>
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/build.xml
new file mode 100644
index 0000000..160c90e
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker.gui" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/spell.checker.gui.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/spell.checker.gui.bnd
new file mode 100644
index 0000000..288f8c3
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/spell.checker.gui.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.gui
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/src/spell/gui/SpellCheckerGui.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/src/spell/gui/SpellCheckerGui.java
new file mode 100644
index 0000000..d7af6ff
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker.gui/src/spell/gui/SpellCheckerGui.java
@@ -0,0 +1,133 @@
+/*
+ * 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 spell.gui;
+
+import org.apache.felix.ipojo.annotations.*;
+import spell.services.SpellChecker;
+
+import javax.swing.*;
+
+/**
+ * A very simple Gui interacting with the CheckSpeller service
+ */
+@Component // It's a component
+@Instantiate // We declarare an instance
+public class SpellCheckerGui extends JFrame {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Swing component where the user write the passage to check.
+ */
+ private JTextField passage = null;
+
+ /**
+ * Area where the result is displayed.
+ */
+ private JLabel result = null;
+
+ /**
+ * Service dependency on the SpellChecker.
+ */
+ @Requires // It's a service dependency
+ private SpellChecker checker;
+
+ /**
+ * Constructor.
+ * Initialize the GUI.
+ */
+ public SpellCheckerGui() {
+ super();
+ initComponents();
+ this.setTitle("Spellchecker Gui");
+ }
+
+ /**
+ * Initialize the Swing Gui.
+ */
+ private void initComponents() {
+ java.awt.GridBagConstraints gridBagConstraints;
+
+ // The check button
+ JButton checkButton = new JButton();
+ result = new JLabel();
+ passage = new JTextField();
+
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Stop Felix...
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+
+ checkButton.setText("Check");
+ checkButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ check();
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(checkButton, gridBagConstraints);
+
+ result.setPreferredSize(new java.awt.Dimension(175, 20));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(result, gridBagConstraints);
+
+ passage.setPreferredSize(new java.awt.Dimension(175, 20));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(passage, gridBagConstraints);
+
+ pack();
+ }
+
+ /**
+ * Check Button action.
+ * Collects the user input and checks it.
+ */
+ private void check() {
+ // TODO
+ }
+
+ /**
+ * Start callback.
+ * This method will be called when the instance becomes valid.
+ * It set the Gui visibility to true.
+ */
+ @Validate
+ public void start() {
+ // TODO
+ }
+
+ /**
+ * Stop callback.
+ * This method will be called when the instance becomes invalid or stops.
+ * It deletes the Gui.
+ */
+ @Invalidate
+ public void stop() {
+ // TODO
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/build.xml
new file mode 100644
index 0000000..81f1ae7
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/spell.checker.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/spell.checker.bnd
new file mode 100644
index 0000000..eed332d
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/spell.checker.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.checker
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/src/spell/checker/SpellCheck.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/src/spell/checker/SpellCheck.java
new file mode 100644
index 0000000..365dee2
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.checker/src/spell/checker/SpellCheck.java
@@ -0,0 +1,48 @@
+/*
+ * 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 spell.checker;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import spell.services.DictionaryService;
+import spell.services.SpellChecker;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+//TODO
+public class SpellCheck implements SpellChecker {
+
+ //TODO
+
+ /**
+ * Implements SpellChecker.check(). Checks the given passage for misspelled words.
+ *
+ * @param passage the passage to spell check.
+ * @return An array of misspelled words or null if no words are misspelled.
+ */
+ public String[] check(String passage) {
+ //TODO
+ return new String[] {};
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/build.xml
new file mode 100644
index 0000000..c7fcc5d
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.english" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/spell.english.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/spell.english.bnd
new file mode 100644
index 0000000..49d73c4
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/spell.english.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.english
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/src/spell/english/EnglishDictionary.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/src/spell/english/EnglishDictionary.java
new file mode 100644
index 0000000..f89bab6
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.english/src/spell/english/EnglishDictionary.java
@@ -0,0 +1,46 @@
+/*
+ * 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 spell.english;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import spell.services.DictionaryService;
+
+/**
+ * An implementation of the Dictionary service containing English words
+ * see DictionaryService for details of the service.
+ **/
+@Component // It's an iPOJO Component
+@Provides // We provide a service
+@Instantiate // We declare an instance of our component
+public class EnglishDictionary implements DictionaryService {
+
+ /**
+ * Implements DictionaryService.checkWord(). Determines
+ * if the passed in word is contained in the dictionary.
+ * @param word the word to be checked.
+ * @return true if the word is in the dictionary,
+ * false otherwise.
+ **/
+ public boolean checkWord(String word) {
+ //TODO
+ return false;
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/build.xml
new file mode 100644
index 0000000..99117cf
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/build.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.services" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../tasks/bnd-${bnd.version}.jar"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ </target>
+
+ <target name="compile" depends="clean">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ />
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/spell.services.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/spell.services.bnd
new file mode 100644
index 0000000..b05800e
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/spell.services.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Export-Package: spell.services
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/DictionaryService.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/DictionaryService.java
new file mode 100644
index 0000000..634b30a
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/DictionaryService.java
@@ -0,0 +1,30 @@
+/*
+ * 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 spell.services;
+
+public interface DictionaryService {
+
+ /**
+ * Check for the existence of a word.
+ * @param word the word to be checked.
+ * @return true if the word is in the dictionary,
+ * false otherwise.
+ **/
+ public boolean checkWord(String word);
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/SpellChecker.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/SpellChecker.java
new file mode 100644
index 0000000..34424fb
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/skeleton/spell.services/src/spell/services/SpellChecker.java
@@ -0,0 +1,24 @@
+/*
+ * 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 spell.services;
+
+public interface SpellChecker
+{
+ //TODO
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/build.xml
new file mode 100644
index 0000000..58f5829
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/build.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker.example" default="package" basedir=".">
+
+ <target name="clean">
+ <ant dir="spell.services" target="clean"/>
+ <ant dir="spell.english" target="clean"/>
+ <ant dir="spell.checker" target="clean"/>
+ <ant dir="spell.checker.gui" target="clean"/>
+ </target>
+
+ <target name="package">
+ <ant dir="spell.services" target="package"/>
+ <ant dir="spell.english" target="package"/>
+ <ant dir="spell.checker" target="package"/>
+ <ant dir="spell.checker.gui" target="package"/>
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/build.xml
new file mode 100644
index 0000000..b54d397
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker.gui" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/spell.checker.gui.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/spell.checker.gui.bnd
new file mode 100644
index 0000000..288f8c3
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/spell.checker.gui.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.gui
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/src/spell/gui/SpellCheckerGui.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/src/spell/gui/SpellCheckerGui.java
new file mode 100644
index 0000000..fe0a16e
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker.gui/src/spell/gui/SpellCheckerGui.java
@@ -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 spell.gui;
+
+import org.apache.felix.ipojo.annotations.*;
+import spell.services.SpellChecker;
+
+import javax.swing.*;
+
+/**
+ * A very simple Gui interacting with the CheckSpeller service
+ */
+@Component
+@Instantiate
+public class SpellCheckerGui extends JFrame {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Swing component where the user write the passage to check.
+ */
+ private JTextField passage = null;
+
+ /**
+ * Area where the result is displayed.
+ */
+ private JLabel result = null;
+
+ /**
+ * Service dependency on the SpellChecker.
+ */
+ @Requires
+ private SpellChecker checker;
+
+ /**
+ * Constructor.
+ * Initialize the GUI.
+ */
+ public SpellCheckerGui() {
+ super();
+ initComponents();
+ this.setTitle("Spellchecker Gui");
+ }
+
+ /**
+ * Initialize the Swing Gui.
+ */
+ private void initComponents() {
+ java.awt.GridBagConstraints gridBagConstraints;
+
+ // The check button
+ JButton checkButton = new JButton();
+ result = new JLabel();
+ passage = new JTextField();
+
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Stop Felix...
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+
+ checkButton.setText("Check");
+ checkButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ check();
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(checkButton, gridBagConstraints);
+
+ result.setPreferredSize(new java.awt.Dimension(175, 20));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(result, gridBagConstraints);
+
+ passage.setPreferredSize(new java.awt.Dimension(175, 20));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
+ getContentPane().add(passage, gridBagConstraints);
+
+ pack();
+ }
+
+ /**
+ * Check Button action.
+ * Collects the user input and checks it.
+ */
+ private void check() {
+ String[] result = checker.check(passage.getText());
+ if (result != null) {
+ this.result.setText(result.length + " word(s) are misspelled");
+ } else {
+ this.result.setText("All words are correct");
+ }
+ }
+
+ /**
+ * Start callback.
+ * This method will be called when the instance becomes valid.
+ * It set the Gui visibility to true.
+ */
+ @Validate
+ public void start() {
+ this.setVisible(true);
+ }
+
+ /**
+ * Stop callback.
+ * This method will be called when the instance becomes invalid or stops.
+ * It deletes the Gui.
+ */
+ @Invalidate
+ public void stop() {
+ this.dispose();
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/build.xml
new file mode 100644
index 0000000..6764748
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.checker" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/spell.checker.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/spell.checker.bnd
new file mode 100644
index 0000000..eed332d
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/spell.checker.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.checker
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/src/spell/checker/SpellCheck.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/src/spell/checker/SpellCheck.java
new file mode 100644
index 0000000..1846566
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.checker/src/spell/checker/SpellCheck.java
@@ -0,0 +1,78 @@
+/*
+ * 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 spell.checker;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import spell.services.DictionaryService;
+import spell.services.SpellChecker;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+@Component
+@Provides
+@Instantiate
+public class SpellCheck implements SpellChecker {
+
+ @Requires // This is a service dependency.
+ private DictionaryService dictionary;
+
+ /**
+ * Implements SpellChecker.check(). Checks the given passage for misspelled words.
+ *
+ * @param passage the passage to spell check.
+ * @return An array of misspelled words or null if no words are misspelled.
+ */
+ public String[] check(String passage) {
+ // No misspelled words for an empty string.
+ if ((passage == null) || (passage.length() == 0)) {
+ return null;
+ }
+
+ List<String> errorList = new ArrayList<String>();
+
+ // Tokenize the passage using spaces and punctuation.
+ StringTokenizer st = new StringTokenizer(passage, " ,.!?;:");
+
+ // Loop through each word in the passage.
+ while (st.hasMoreTokens()) {
+ String word = st.nextToken();
+
+ // Check the current word.
+ if (!dictionary.checkWord(word)) {
+ // If the word is not correct, then add it
+ // to the incorrect word list.
+ errorList.add(word);
+ }
+ }
+
+ // Return null if no words are incorrect.
+ if (errorList.size() == 0) {
+ return null;
+ }
+
+ // Return the array of incorrect words.
+ System.out.println("Wrong words:" + errorList);
+ return errorList.toArray(new String[errorList.size()]);
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/build.xml
new file mode 100644
index 0000000..f17e1b5
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.english" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="lib.dir" value="libs"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../../tasks/bnd-${bnd.version}.jar"/>
+ <taskdef name="ipojo" classpath="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar"
+ classname="org.apache.felix.ipojo.task.IPojoTask"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ <delete dir="${lib.dir}"/>
+ </target>
+
+ <target name="buildclasspath">
+ <copy file="../spell.services/output/spell.services.jar" todir="${lib.dir}"/>
+ <copy file="../../tasks/org.apache.felix.ipojo.ant-${ipojo.manipulator.version}.jar" todir="${lib.dir}"/>
+ </target>
+
+ <path id="classpath">
+ <fileset dir="${lib.dir}" includes="**/*.jar"/>
+ </path>
+
+ <target name="compile" depends="clean, buildclasspath">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ classpathref="classpath"
+ />
+
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+
+ <ipojo
+ input="${output.dir}/${ant.project.name}.jar"
+ classpathref="classpath"
+ />
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/spell.english.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/spell.english.bnd
new file mode 100644
index 0000000..49d73c4
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/spell.english.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Private-Package: spell.english
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/src/spell/english/EnglishDictionary.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/src/spell/english/EnglishDictionary.java
new file mode 100644
index 0000000..4d94a65
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.english/src/spell/english/EnglishDictionary.java
@@ -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 spell.english;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import spell.services.DictionaryService;
+
+/**
+ * An implementation of the Dictionary service containing English words
+ * see DictionaryService for details of the service.
+ **/
+@Component // It's an iPOJO Component
+@Provides // We provide a service
+@Instantiate // We declare an instance of our component
+public class EnglishDictionary implements DictionaryService {
+
+ // The set of words contained in the dictionary.
+ String[] dictionary = { "welcome", "to", "the", "ipojo", "tutorial" };
+
+ /**
+ * Implements DictionaryService.checkWord(). Determines
+ * if the passed in word is contained in the dictionary.
+ * @param word the word to be checked.
+ * @return true if the word is in the dictionary,
+ * false otherwise.
+ **/
+ public boolean checkWord(String word) {
+ word = word.toLowerCase();
+
+ // This is very inefficient
+ for (String dict : dictionary) {
+ if (dict.equals(word)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/build.xml b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/build.xml
new file mode 100644
index 0000000..13eabd5
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/build.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+
+<!--
+ ~ 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 name="spell.services" default="package" basedir="">
+
+ <property name="src.dir" value="src"/>
+ <property name="build.dir" value="output/classes"/>
+ <property name="output.dir" value="output"/>
+
+ <taskdef resource="aQute/bnd/ant/taskdef.properties"
+ classpath="../../tasks/bnd-${bnd.version}.jar"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${output.dir}"/>
+ </target>
+
+ <target name="compile" depends="clean">
+ <mkdir dir="${output.dir}"/>
+ <mkdir dir="${build.dir}"/>
+
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}"
+ debug="on"
+ />
+ </target>
+
+ <target name="package" depends="compile">
+ <bnd
+ classpath="${build.dir}"
+ failok="false"
+ exceptions="true"
+ files="${ant.project.name}.bnd"
+ output="${output.dir}"/>
+ </target>
+
+</project>
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/spell.services.bnd b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/spell.services.bnd
new file mode 100644
index 0000000..b05800e
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/spell.services.bnd
@@ -0,0 +1,19 @@
+###
+# 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.
+###
+Export-Package: spell.services
\ No newline at end of file
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/DictionaryService.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/DictionaryService.java
new file mode 100644
index 0000000..af58257
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/DictionaryService.java
@@ -0,0 +1,31 @@
+/*
+ * 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 spell.services;
+
+public interface DictionaryService {
+
+ /**
+ * Check for the existence of a word.
+ * @param word the word to be checked.
+ * @return true if the word is in the dictionary,
+ * false otherwise.
+ **/
+ public boolean checkWord(String word);
+
+}
diff --git a/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/SpellChecker.java b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/SpellChecker.java
new file mode 100644
index 0000000..c951da0
--- /dev/null
+++ b/ipojo/runtime/distributions/ten-minutes-tutorial/src/main/solution/spell.services/src/spell/services/SpellChecker.java
@@ -0,0 +1,40 @@
+/*
+ * 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 spell.services;
+
+/**
+ * A simple service interface that defines a spell checker service.
+ * A spell checker service checks the spelling of all words in a
+ * given passage. A passage is any number of words separated by
+ * a space character and the following punctuation marks: comma,
+ * period, exclamation mark, question mark, semi-colon, and colon.
+**/
+public interface SpellChecker
+{
+ /**
+ * Checks a given passage for spelling errors. A passage is any
+ * number of words separated by a space and any of the following
+ * punctuation marks: comma (,), period (.), exclamation mark (!),
+ * question mark (?), semi-colon (;), and colon(:).
+ * @param passage the passage to spell check.
+ * @return An array of misspelled words or null if no
+ * words are misspelled.
+ **/
+ public String[] check(String passage);
+}
diff --git a/ipojo/runtime/ipojo-gogo-commands/changelog.txt b/ipojo/runtime/ipojo-gogo-commands/changelog.txt
new file mode 100644
index 0000000..d1c7cfc
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/changelog.txt
@@ -0,0 +1,176 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.1.0 to 1.10.1
+-----------------------------
+
+Important: The iPOJO's gogo commands were moved to the iPOJO runtime project.
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+Version 1.1.0
+-------------
+** Bug
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+
+** Task
+ * [FELIX-3921] - Update pom to latest Felix's parent
+
+Version 1.0.1
+-------------
+** Bug
+ * [FELIX-2632] Arch Gogo is not compatible with the new gogo (0.6.1)
+
+Version 1.0.0
+-------------
+ * Initial release
diff --git a/ipojo/runtime/ipojo-gogo-commands/obr.xml b/ipojo/runtime/ipojo-gogo-commands/obr.xml
new file mode 100644
index 0000000..8832ddf
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/obr.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<obr>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.architecture.Architecture)" multiple="true" name="service" optional="true">Import Service org.apache.felix.ipojo.architecture.Architecture</require>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.Factory)" multiple="false" name="service" optional="true">Import Service org.apache.felix.ipojo.Factory</require>
+ <require extend="false" filter="(service=org.apache.felix.ipojo.HandlerFactory)" multiple="false" name="service" optional="true">Import Service org.apache.felix.ipojo.HandlerFactory</require>
+ <require extend="false" filter="(&(name=requires)(namespace=org.apache.felix.ipojo))" multiple="false" optional="false" name="ipojo.handler">Requires Handler</require>
+</obr>
\ No newline at end of file
diff --git a/ipojo/runtime/ipojo-gogo-commands/pom.xml b/ipojo/runtime/ipojo-gogo-commands/pom.xml
new file mode 100644
index 0000000..8843cd4
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/pom.xml
@@ -0,0 +1,126 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>Apache Felix iPOJO Gogo Command</name>
+ <artifactId>org.apache.felix.ipojo.gogo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <description>
+ Provides commands for the Gogo shell to introspect the iPOJO ecosystem.
+ </description>
+ <url>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-arch-command.html
+ </url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.12.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <version>0.6.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>Apache Felix iPOJO Gogo Command</Bundle-Name>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+ <Bundle-Description>
+ Gogo commands for iPOJO
+ </Bundle-Description>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-arch-command.html
+ </Bundle-DocURL>
+ <Private-Package>org.apache.felix.ipojo.arch.gogo</Private-Package>
+ <Import-Package>
+ org.apache.felix.service.command;version=0.6.0, *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.10.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1c61161
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,11 @@
+I. Included Third-Party Software
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/src/main/appended-resources/META-INF/NOTICE
diff --git a/ipojo/runtime/ipojo-gogo-commands/src/main/java/org/apache/felix/ipojo/arch/gogo/Arch.java b/ipojo/runtime/ipojo-gogo-commands/src/main/java/org/apache/felix/ipojo/arch/gogo/Arch.java
new file mode 100644
index 0000000..b396ed6
--- /dev/null
+++ b/ipojo/runtime/ipojo-gogo-commands/src/main/java/org/apache/felix/ipojo/arch/gogo/Arch.java
@@ -0,0 +1,355 @@
+/*
+ * 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.arch.gogo;
+
+import static java.lang.String.format;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.service.command.Descriptor;
+
+/**
+ * iPOJO Arch command giving information about the current
+ * system architecture. This is a Gogo command.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@Component(public_factory = false, immediate = true)
+@Instantiate
+@Provides(specifications = Arch.class)
+public class Arch {
+
+ /**
+ * Defines the command scope (ipojo).
+ */
+ @ServiceProperty(name = "osgi.command.scope", value = "ipojo")
+ String m_scope;
+
+ /**
+ * Defines the functions (commands).
+ */
+ @ServiceProperty(name = "osgi.command.function", value = "{}")
+ String[] m_function = new String[] {
+ "instances",
+ "instance",
+ "factory",
+ "component",
+ "factories",
+ "components",
+ "handlers",
+ "extensions"
+ };
+
+ /**
+ * Instance architecture services.
+ */
+ @Requires(optional = true)
+ private Architecture[] m_archs;
+
+ /**
+ * Factory services.
+ */
+ @Requires(optional = true)
+ private Factory[] m_factories;
+
+ /**
+ * Handler Factory services.
+ */
+ @Requires(optional = true)
+ private HandlerFactory[] m_handlers;
+
+ /**
+ * The instance declaration services.
+ */
+ @Requires(optional = true)
+ private InstanceDeclaration[] m_instances;
+
+ /**
+ * The type declaration services.
+ */
+ @Requires(optional = true)
+ private TypeDeclaration[] m_types;
+
+ /**
+ * The extension declaration services.
+ */
+ @Requires(optional = true)
+ private ExtensionDeclaration[] m_extensions;
+
+ /**
+ * Displays iPOJO instances.
+ */
+ @Descriptor("Display iPOJO instances")
+ public void instances() {
+ StringBuilder buffer = new StringBuilder();
+ for (Architecture m_arch : m_archs) {
+ InstanceDescription instance = m_arch.getInstanceDescription();
+ if (instance.getState() == ComponentInstance.VALID) {
+ buffer.append(format("Instance %s -> valid%n", instance.getName()));
+ }
+ if (instance.getState() == ComponentInstance.INVALID) {
+ buffer.append(format("Instance %s -> invalid%n", instance.getName()));
+ }
+ if (instance.getState() == ComponentInstance.STOPPED) {
+ buffer.append(format("Instance %s -> stopped%n", instance.getName()));
+ }
+ }
+
+ for (InstanceDeclaration instance : m_instances) {
+ // Only print unbound instances (others already printed above)
+ if (!instance.getStatus().isBound()) {
+ buffer.append(format("Instance %s of type %s is not bound.%n",
+ name(instance.getConfiguration()),
+ instance.getConfiguration().get("component")));
+ buffer.append(format(" Reason: %s", instance.getStatus().getMessage()));
+ buffer.append("\n");
+ }
+ }
+
+ if (buffer.length() == 0) {
+ buffer.append("No instances \n");
+ }
+
+ System.out.println(buffer.toString());
+ }
+
+ private String name(Dictionary<String, Object> configuration) {
+ String name = (String) configuration.get("instance.name");
+ if (name == null) {
+ name = "unnamed";
+ }
+ return name;
+ }
+
+ /**
+ * Displays the architecture of a specific instance.
+ * @param instance the instance name
+ */
+ @Descriptor("Display the architecture of a specific instance")
+ public void instance(@Descriptor("target instance name") String instance) {
+
+ StringBuilder sb = new StringBuilder();
+
+ for (Architecture m_arch : m_archs) {
+ InstanceDescription id = m_arch.getInstanceDescription();
+ if (id.getName().equalsIgnoreCase(instance)) {
+ sb.append(id.getDescription());
+ sb.append('\n');
+ }
+ }
+
+ for (InstanceDeclaration instanceDeclaration : m_instances) {
+ if (!instanceDeclaration.getStatus().isBound()) {
+ if (instance.equals(name(instanceDeclaration.getConfiguration()))) {
+ sb.append(format("InstanceDeclaration %s not bound to its factory%n", instance));
+ sb.append(format(" type: %s%n", instanceDeclaration.getComponentName()));
+ sb.append(format(" reason: %s%n", instanceDeclaration.getStatus().getMessage()));
+ Throwable throwable = instanceDeclaration.getStatus().getThrowable();
+ if (throwable != null) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ throwable.printStackTrace(new PrintStream(os));
+ sb.append(" throwable: ");
+ sb.append(os.toString());
+ }
+ }
+ }
+ }
+
+ if (sb.length() == 0) {
+ System.err.printf("Instance named '%s' not found", instance);
+ } else {
+ System.out.print(sb);
+ }
+
+ }
+
+ /**
+ * Displays the information about a specific factory.
+ * Note that factory name are not unique, so all matching
+ * factories are displayed.
+ * @param name the factory name
+ */
+ @Descriptor("Display the information about a specific factory / component")
+ public void component(@Descriptor("target factory name") String name) {
+ factory(name);
+ }
+
+ /**
+ * Displays the information about a specific factory.
+ * Note that factory name are not unique, so all matching
+ * factories are displayed.
+ * @param name the factory name
+ */
+ @Descriptor("Display the information about a specific factory")
+ public void factory(@Descriptor("target factory name") String name) {
+
+ List<Factory> factories = new ArrayList<Factory>();
+ List<TypeDeclaration> types = new ArrayList<TypeDeclaration>();
+
+ // Looking for public factories
+ for (Factory factory : m_factories) {
+ if (factory.getName().equalsIgnoreCase(name)) {
+ factories.add(factory);
+ }
+ }
+
+ // Looking for all unbound or private bound types
+ for (TypeDeclaration type : m_types) {
+ if (name.equalsIgnoreCase(type.getComponentName())) {
+ // (Public + Unbound) or private types have no exported factories
+ if (!type.isPublic() || (!type.getStatus().isBound() && type.isPublic())) {
+ types.add(type);
+ }
+ }
+ }
+
+ if (factories.isEmpty() && types.isEmpty()) {
+ System.err.println("Factory " + name + " not found");
+ return;
+ }
+
+ // Display found factories and types
+ for (Factory factory : factories) {
+ System.out.println(factory.getComponentDescription());
+ }
+ for (TypeDeclaration type : types) {
+ if (!type.getStatus().isBound()) {
+ // Unbound: maybe private or public type
+ System.out.printf("Factory %s is not bound%n", type.getComponentName());
+ System.out.printf(" reason: %s%n", type.getStatus().getMessage());
+ Throwable throwable = type.getStatus().getThrowable();
+ if (throwable != null) {
+ System.out.print(" throwable: ");
+ throwable.printStackTrace(System.out);
+ }
+ } else {
+ // Bound, this is only a private factory
+ System.out.printf("Factory %s is bound - Private%n", type.getComponentName());
+ }
+ }
+
+ }
+
+ /**
+ * Displays the list of public iPOJO factories.
+ */
+ @Descriptor("Display iPOJO factories / components")
+ public void components() {
+ factories();
+ }
+
+ /**
+ * Displays the list of public iPOJO factories.
+ */
+ @Descriptor("Display iPOJO factories")
+ public void factories() {
+ StringBuilder buffer = new StringBuilder();
+ for (Factory m_factory : m_factories) {
+ if (m_factory.getMissingHandlers().size() == 0) {
+ buffer.append(format("Factory %s (VALID)%n", m_factory.getName()));
+ } else {
+ buffer.append(format("Factory %s (INVALID: %s)%n",
+ m_factory.getName(),
+ m_factory.getMissingHandlers()));
+ }
+ }
+
+ for (TypeDeclaration type : m_types) {
+ if (!type.isPublic()) {
+ // Private factories: always display them
+ // Cannot display much more than presence/absence since the TypeDeclaration API does not
+ // give access to the underlying Factory or description (if valid)
+ if (type.getStatus().isBound()) {
+ buffer.append(format("Factory %s (UNKNOWN) - Private%n", type.getComponentName()));
+ } else {
+ // Unbound type means that required extension is not available
+ // We'll say that the factory is INVALID even if in reality it's not even instantiated
+ buffer.append(format("Factory %s (INVALID) - Private%n", type.getComponentName()));
+ buffer.append(format(" -> %s", type.getStatus().getMessage()));
+ }
+ } else {
+ if (!type.getStatus().isBound()) {
+ buffer.append(format("Factory %s is not bound%n", type.getComponentName()));
+ buffer.append(format(" -> %s%n", type.getStatus().getMessage()));
+ }
+ }
+ }
+
+ if (buffer.length() == 0) {
+ buffer.append("No factories \n");
+ }
+
+ System.out.println(buffer.toString());
+ }
+
+ /**
+ * Displays the list of available handlers.
+ */
+ @Descriptor("Display iPOJO handlers")
+ public void handlers() {
+ PrintStream out = System.out;
+ for (HandlerFactory m_handler : m_handlers) {
+ String name = m_handler.getHandlerName();
+ if ("composite".equals(m_handler.getType())) {
+ name = name + " [composite]";
+ }
+ if (m_handler.getMissingHandlers().size() == 0) {
+ out.println("Handler " + name + " (VALID)");
+ } else {
+ out.println("Handler " + name + " (INVALID : " + m_handler.getMissingHandlers() + ")");
+ }
+ }
+
+ for (TypeDeclaration type : m_types) {
+ if (!type.getStatus().isBound()) {
+ out.println("HandlerFactory " + type.getComponentName() + " is not bound");
+ out.println(" -> " + type.getStatus().getMessage());
+ }
+ }
+ }
+
+ /**
+ * Displays the list of available extensions.
+ */
+ @Descriptor("Display iPOJO extensions")
+ public void extensions() {
+ PrintStream out = System.out;
+ out.println("Available extensions:");
+ for (ExtensionDeclaration extension : m_extensions) {
+ out.println(" * " + extension.getExtensionName());
+ }
+ }
+
+}
diff --git a/ipojo/runtime/karaf-feature/changelog.txt b/ipojo/runtime/karaf-feature/changelog.txt
new file mode 100644
index 0000000..0d7fa86
--- /dev/null
+++ b/ipojo/runtime/karaf-feature/changelog.txt
@@ -0,0 +1,398 @@
+Changes from 1.12.0 to 1.12.1
+-----------------------------
+
+** Bug
+ * [FELIX-3836] - NPE when calling InstanceDescription.getDescription()
+ * [FELIX-4565] - Occasional ArrayIndexOutOfBoundException in iPOJO's ProvidedServiceHandler
+ * [FELIX-4646] - @Context(Context.Source.INSTANCE) does not inject bundle context
+ * [FELIX-4713] - Error in ProvidedServiceHandler.checkProvidedService : only the first service is checked
+ * [FELIX-4715] - instance bundle context injection does not works
+ * [FELIX-4716] - Bundle org.apache.felix.ipojo physically contains OSGi API classes
+ * [FELIX-4717] - Cannot use the stream API on injected collections
+ * [FELIX-4728] - InstanceManager concurrency issue
+
+Changes from 1.11.2 to 1.12.0
+-----------------------------
+
+** Bug
+ * [FELIX-4464] - Wrong configuration admin package import / export clause
+ * [FELIX-4488] - Attempt to create nullable object for non-interface service
+
+** Improvement
+ * [FELIX-4482] - Use scope=provided for OSGi APIs dependencies
+ * [FELIX-4490] - IPOJO allows "instance.name" property to be an empty String
+
+** New Feature
+ * [FELIX-4476] - Java 8 Support
+
+** Sub-task
+ * [FELIX-4508] - Update to ASM 5.0.2
+ * [FELIX-4509] - Change the frame computation strategy
+ * [FELIX-4510] - Support lambda expression
+
+Changes from 1.11.1 to 1.11.2
+-----------------------------
+
+** Bug
+ * [FELIX-4229] - Provide a way to obtain the component's BundleContext (other than constructor injection)
+ * [FELIX-4419] - Open access to InstanceDeclaration and TypeDeclaration
+ * [FELIX-4432] - DefaultServiceRankingInterceptor holds duplicate dependencies
+ * [FELIX-4448] - Invalid dynamism management when an interceptor implements both Tracking and Ranking interceptors
+ * [FELIX-4449] - The ConfigurationListener list contains duplicates and fires update on unchanged configurations
+
+** Improvement
+ * [FELIX-3931] - Provide a handler to inject the bundle context
+ * [FELIX-4160] - Create an Maven Parent POM for iPOJO
+
+Changes from 1.11.0 to 1.11.1
+-----------------------------
+
+** Bug
+ * [FELIX-4335] - PropertyDescription does not allow retrieving the current value of the represented property
+ * [FELIX-4374] - iPOJO: ConcurrentModificationException in ProvidedService
+ * [FELIX-4386] - Deadlock while creating composite instances programmatically
+
+** Improvement
+ * [FELIX-4292] - @Component 'propagation' attribute has wrong default value
+
+Changes from 1.10.1 to 1.11.0
+-----------------------------
+
+** Bug
+ * [FELIX-4115] - NPE in DependencyModel.getService() when @Bind method throws an exception
+ * [FELIX-4132] - @Modified not working on Equinox
+ * [FELIX-4138] - TypeDeclaration calls factory.dispose() even if it already has been disposed (externally)
+ * [FELIX-4139] - package conflict with ipojo-annotations and ipojo-runtime
+ * [FELIX-4164] - Instance / Component matching regression
+ * [FELIX-4172] - Updated method called twice at the bundle start
+ * [FELIX-4183] - Wrong Javadoc of TrackerCustomizer addingService method
+ * [FELIX-4199] - The filter based service tracking interceptor should always be created
+ * [FELIX-4200] - Only the last iPOJO Tracking interceptor is modifying the reference
+ * [FELIX-4204] - Service Dependencies with a callback without a type attribute must be rejected
+ * [FELIX-4207] - ipojo @Component with propagation set to true doesn't propagate properties
+ * [FELIX-4218] - NPE with field annotated with both @Property and @ServiceProperty
+ * [FELIX-4236] - Unvalued properties should be part of the instance's architecture
+ * [FELIX-4247] - Memory leak with ServiceUsage and inner class (Listener style)
+ * [FELIX-4248] - ServiceUsage ThreadLocal removal
+ * [FELIX-4250] - Specification deduction broken when the method does not start with the 'bind' prefix
+ * [FELIX-4251] - The @Bind annotation should use Class instead of String
+ * [FELIX-4261] - NPE when an instance is declared without a configuration using the @ConfigurationTracker
+ * [FELIX-4268] - Duplicated name errors always happen when there are 2 factories with the same name
+
+** Improvement
+ * [FELIX-4143] - Improve @Configuration management performances
+ * [FELIX-4216] - Allow @Property without name in constructors
+ * [FELIX-4228] - Improve dependency identification in log messages and exceptions
+ * [FELIX-4232] - Service Dependency Interceptors should be part of the instance architecture
+ * [FELIX-4252] - Make Extender's ThreadPool size configurable
+ * [FELIX-4262] - QueueServices should be observable
+ * [FELIX-4263] - iPOJO Core should use ranged imports
+ * [FELIX-4264] - JobInfo should provide a way to identify the kind of task
+
+** New Feature
+ * [FELIX-4146] - Add getInstances and getInstanceNames in the Factory interface
+ * [FELIX-4147] - Add getProvidedService in ProvidedServiceDescription and allow external service management
+ * [FELIX-4215] - Extend manipulation metadata with argument names
+ * [FELIX-4231] - Provide service binding interceptors
+ * [FELIX-4265] - Provides a recorder for startup events
+ * [FELIX-4267] - Define Apache Karaf features for iPOJO
+
+** Task
+ * [FELIX-3925] - Merge the temporal dependency handler within the service dependency handler
+ * [FELIX-4133] - Add distribution creation in the iPOJO runtime build
+ * [FELIX-4134] - Move integration-tests to the reactor
+ * [FELIX-4136] - Document service dependency interceptors
+ * [FELIX-4151] - Fix mistakes in the javadoc tags
+ * [FELIX-4156] - Fix versions of maven plugins
+ * [FELIX-4217] - Ensure compatibility between Aries Blueprint and iPOJO
+ * [FELIX-4245] - Deadlock in Dependency
+ * [FELIX-4270] - Bump iPOJO package version to 1.11.0
+
+** Sub-task
+ * [FELIX-4239] - Extend service dependency documentation with the 'exception' attribute.
+ * [FELIX-4240] - Support the 'exception' attribute in service dependencies
+ * [FELIX-4242] - Support the 'timeout' attribute in service dependencies
+ * [FELIX-4243] - Define the dependency configuration matrix and improve error detection
+ * [FELIX-4244] - Extend the service dependency documentation with the timeout attribute
+ * [FELIX-4257] - Allow the dependency handler to track the entry and exit of inner class methods
+
+Changes from 1.10.0 to 1.10.1
+-----------------------------
+
+** Bug
+ * [FELIX-4072] - onGet and onSet methods do not provide the reference on the pojo object
+ * [FELIX-4076] - Useless locking on getRequiredHandler
+ * [FELIX-4077] - Fix documentation urls in maven projects
+ * [FELIX-4089] - Extender do not deactivate managed components when stopped
+ * [FELIX-4096] - NPE when retrieve required and missing handler on a disposed factory
+ * [FELIX-4105] - Factories not disposed when their bundle is leaving
+ * [FELIX-4106] - Defensive service registration and update
+ * [FELIX-4108] - Deadlock in the new extender
+ * [FELIX-4109] - ComponentTypeDescription.addProperty() ignore immutable parameter
+ * [FELIX-4113] - Factories not disposed when the extension provider is leaving
+ * [FELIX-4114] - iPOJO ProvidedServiceDescription does not expose policy & CreationStrategy
+ * [FELIX-4123] - Deadlock in new extender because of factory lock used in removedService
+ * [FELIX-4127] - Configuration tracker bug when starting and stopping iPOJO successively
+ * [FELIX-4129] - Cannot change the optionality of a dependency
+
+** Improvement
+ * [FELIX-1430] - Notification mechanism on bind/unbind events
+ * [FELIX-4073] - PrimitiveHandler.attach(ComponentInstance) is final
+ * [FELIX-4119] - Allow customization of DependencyHandler created Callbacks
+
+** New Feature
+ * [FELIX-4116] - Ability to listen for component service dependencies, providings, configuration properties, ...
+ * [FELIX-4120] - Allow external entity to interact during the service resolution
+ * [FELIX-4125] - Provide 'components' and 'component' commands
+ * [FELIX-4130] - Allow retrieving the component instance from the instance description
+ * [FELIX-4131] - Explicitly set configuration's location when the configuration is null
+
+** Task
+ * [FELIX-4092] - Move 'annotation' module from 'runtime' to 'manipulator' project
+ * [FELIX-4103] - Skip deployment of it-tests
+ * [FELIX-4104] - Do not run integration-tests in the default build
+ * [FELIX-4124] - Move arch-gogo to runtime
+
+Changes from 1.8.6 to 1.10.0
+----------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3843] - ClassCastException when listing service properties of a non-ComponentFactory Factory service
+ * [FELIX-3895] - iPOJO instance is not shown (with the "arch" commands) if constructor is failing
+ * [FELIX-3896] - Null reference are injected with @Bind(optional=false) method on iPOJO components
+ * [FELIX-3918] - iPOJO Logger cannot be dynamically configured on Equinox and KF
+ * [FELIX-3919] - iPOJO Proxies strategy cannot be configured dynamically on Equinox and KF
+ * [FELIX-3920] - Creation Strategy does not work on KF3
+ * [FELIX-3974] - Properties cannot be set as immutable using annotations
+ * [FELIX-3995] - Missing options in Bind annotation
+ * [FELIX-4041] - Properties starting with . should not be propagated
+ * [FELIX-4048] - @Requires handler does not fail when no specification can be found
+ * [FELIX-4053] - Avoid @StaticServiceProperty to be used on classes
+ * [FELIX-4054] - Use current factory version to generate instance name if required
+
+** Improvement
+ * [FELIX-3860] - factories and instances iPOJO gogo commands should show the "public=false" instances/factories
+ * [FELIX-3932] - Allow dependency filter's to get context-source variables
+ * [FELIX-4040] - Implement config admin support to handle binding location properly
+ * [FELIX-4045] - Chain Exceptions when possible
+
+** New Feature
+ * [FELIX-4034] - Instance configuration DSL
+
+** Task
+ * [FELIX-3892] - Upgrade runtime codebase to Java 5
+ * [FELIX-3903] - Migrate tests to pax exam 3
+ * [FELIX-3921] - Update pom to latest Felix's parent
+ * [FELIX-3948] - Define a new extender model
+ * [FELIX-3978] - Check that we don't use java 6+ API
+
+** Wish
+ * [FELIX-3926] - Provide metadata for the Extender namespace
+
+Changes from the 1.8.4 to 1.8.6
+-------------------------------
+
+** Bug
+ * [FELIX-3742] - Implementing class fails to load unless super interface's (interface extended by implemented interface) package is imported.
+ * [FELIX-3789] - Deadlock due to synchronization on INSTANCE_NAME
+ * [FELIX-3819] - The export directive of iPOJO is wrong
+
+Changes from the 1.8.2 to 1.8.4
+--------------------------------
+
+** Bug
+ * [FELIX-3451] - "instance.name" attribute not recognized
+ * [FELIX-3500] - InstanceManager concurrency issue: "A methodID cannot be associated with a method from the POJO class"
+ * [FELIX-3501] - IPojo FactoryStateListener doesn't get notified while stopping factory
+ * [FELIX-3545] - Memory leak when unregistering a component used by an aggregate dependency with an unbind callback
+ * [FELIX-3548] - Concurrent access during startup
+ * [FELIX-3567] - iPOJO Configuration Handler should not reuse the dictionary object from the configuration admin
+ * [FELIX-3576] - iPOJO fails when using constructor injection and expecting BundleContext in ctor
+ * [FELIX-3599] - Problem with 'subservice action="instantiate"' in ipojo composite
+ * [FELIX-3621] - Two dimensional array as argument to a method in a component
+ * [FELIX-3672] - Potential Concurrent Modification Exception when a bundle is stopped
+
+** Improvement
+ * [FELIX-3560] - Extensions to IPojo's Factory and ComponentInstance documentation for custom handlers
+
+Changes from the 1.8.0 to 1.8.2
+-------------------------------
+** Bug
+ * [FELIX-2893] - Properties are not propagate to service by default
+ * [FELIX-2902] - Service properties added by propagation overrides already existing properties
+ * [FELIX-2907] - Problem calling _setInstanceManager on guice enhanced classe
+ * [FELIX-2981] - Unable to remove configuration properties using iPOJO's configuration handler
+ * [FELIX-2989] - Using a Service Controller set to true can trigger a service registration-unregistration-registration sequence
+ * [FELIX-2995] - The service properties are updated despite there is no changes
+ * [FELIX-3009] - Abstract classes as service specifications generates warnings at runtime
+ * [FELIX-3075] - Change to ServiceController status in current trunk does not re-register service
+ * [FELIX-3172] - Error when calling BundleContext.register(Class, Object, Dictionary)
+ * [FELIX-3192] - Service properties are not updated if the properties were already propagated
+ * [FELIX-3271] - On KF, the Instance singleton strategy throws an UnsupportedOperationException when stopping
+ * [FELIX-3323] - Ipojo composite throw ClassCastException when configuration is updated thru ConfigAdmin
+ * [FELIX-3356] - Objectweb ASM Clashes with IPojo
+ * [FELIX-3374] - Use of java.lang.Properties in iPOJO Core
+
+** Improvement
+ * [FELIX-3036] - Add IPOJO-Components header support
+ * [FELIX-3081] - Integrate the online-manipulator in iPOJO Core
+ * [FELIX-3144] - Method interceptors should receive Method or Constructor objects
+ * [FELIX-3155] - Allow identifying iPojo extensions by a namespace qualified name
+ * [FELIX-3190] - iPOJO Factories doesn't give access to the complete Metadata model
+ * [FELIX-3252] - Merge the online manipulator into iPOJO Core
+ * [FELIX-3326] - Accessing IPojo-Component's all inherited classes and all implemented interfaces in PrimitiveTypeDescription
+
+** New Feature
+ * [FELIX-2932] - Allows disabling the asynchronous processing in the iPOJO Extender
+
+Changes from the 1.6.8 to 1.8.0
+-------------------------------
+** Bug
+ * [FELIX-2694] - Instance state not recomputed after reconfiguration when the instance is stopped
+ * [FELIX-2716] - [iPOJO] Failure when creating proxies for classes in java.* packages
+
+** Improvement
+ * [FELIX-2781] - Expose the implementation class as service when no interfaces are found in the hierarchy
+ * [FELIX-1424] - Constructor Injection
+ * [FELIX-1428] - Constructor injection of Configuration properties
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+ * [FELIX-2620] - Change iPojo annotation parameters to follow java naming conventions
+ * [FELIX-2621] - Rename annotations to remove collisions
+ * [FELIX-2622] - Support static service properties that are not mirrored into fields
+ * [FELIX-2688] - iPojo "requires.filters" - Array object instead of Dictionary object
+ * [FELIX-2705] - Provide a way to extend the logger strategy
+ * [FELIX-2742] - Constructor injection of service dependencies
+ * [FELIX-2744] - Add annotations to the maven-ipojo-plugin archetype
+
+Changes from the 1.6.6 to 1.6.8
+-------------------------------
+** Improvement
+ * [FELIX-2688] - iPojo "requires.filters" - Array object instead of Dictionary object
+ * [FELIX-2705] - Provide a way to extend the logger strategy
+
+** Bug
+ * [FELIX-2685] - Wrong Element name when XML namespace contains ':'
+ * [FELIX-2694] - Instance state not recomputed after reconfiguration when the instance is stopped
+
+Changes from the 1.6.4 to 1.6.6
+-------------------------------
+** Improvement
+ * [FELIX-2594] - Have a way to create new custom iPojo handler without having to specify a handler usage
+ * [FELIX-2623] - @Update annotated methods should not require a Dictionary parameter
+
+** Bug
+ * [FELIX-2580] - iPOJO failed to create proxies on service which are not interface
+ * [FELIX-2596] - DependencyHandler.onObjectCreation throws NPE when bundle is refreshed
+ * [FELIX-2603] - wrong behavior of InstanceManager.onSet(..) method
+ * [FELIX-2636] - Cannot control the validity of an iPOJO instance using a configuration property
+
+Changes from the 1.6.2 to 1.6.4
+-------------------------------
+** Improvement
+ * [FELIX-2420] - Enum support for @Property annotation
+ * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController
+ * [FELIX-2472] - Proxies should throw a runtime exception instead of a null pointer exception
+
+** Bug
+ * [FELIX-2561] - Properties set as required instead of optional in the component type descriptions
+
+Changes from the 1.6.0 to 1.6.2
+-------------------------------
+** Bug
+ * [FELIX-2308] - getService is called during the unregistration of a service.
+ * [FELIX-2309] - Potential NPE when a service has abruptly in the smart proxies.
+ * [FELIX-2323] - Unbind method should not be called during the invalidation process if the invalidation does not come from a service departure.
+
+** Improvement
+ * [FELIX-2296] - Access to ServiceReference in iPOJO service.
+
+Changes from the 1.4.0 to 1.6.0
+-------------------------------
+** Bug
+ * [FELIX-1533] - Potential deadlock when stopping the underlying OSGi framework
+ * [FELIX-1965] - iPojo component is made available regardless of exception during validate
+ * [FELIX-2014] - Potential ClassCastException when a service property does not receive a value and is used in the constructor
+ * [FELIX-2019] - The Property value is 'null' in the Architecture description, while the value is well assigned to the component's field.
+ * [FELIX-2052] - Handler require callback are not called if the service (required) is registered before the instance of the handler has been started.
+ * [FELIX-2093] - iPOJO doesn't always use the correct class loader
+
+** Improvement
+ * [FELIX-1425] - Service Proxy Mode
+ * [FELIX-1426] - Service injection with Dynamic Proxies
+ * [FELIX-1427] - Service injection with Smart Proxies
+ * [FELIX-1532] - Be able to set the iPOJO Log Level from BND
+ * [FELIX-1741] - Allows the configuration handler description to retrieve the managed service PID
+ * [FELIX-1854] - Allows instances to directly declares service.* properties (pid, ranking, vendor, description)
+ * [FELIX-1885] - Ease CreationStrategy & iPOJOServiceFactory usage
+ * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified
+
+** New Feature
+ * [FELIX-2132] - Provides a way to control service exposition from the implementation class
+
+
+Changes from 1.2.0 to 1.4.0
+---------------------------
+** Bug
+ * [FELIX-985] - iPOJO analyzes already installed bundle by holding a lock
+ * [FELIX-1002] - iPOJO Static binding policy is not compliant with the Declarative Service static binding policy.
+ * [FELIX-1318] - Case mismatch problem of iPOJO custom handler name
+** Improvement
+ * Update parent pom
+ * [FELIX-936] - Allowing publishing class as services
+ * [FELIX-966] - iPOJO: Better error reporting when getPojoObject return null
+ * [FELIX-982] - Declare iPOJO as a singleton bundle to avoid multiple version of the runtime at the same time
+ * [FELIX-1114] - callback after configuration change needed
+ * [FELIX-1163] - Improve error message when an array cannot be created due to a classloading issue
+ * [FELIX-1182] - iPOJO - reconfiguration : get all properties with the update callback
+
+
+Changes from 1.0.0 to 1.2.0
+---------------------------
+** Bug
+ * [FELIX-797] - Composite Architecture contains duplicate instances
+ * [FELIX-803] - iPOJO Core schema needs to be fixed
+ * [FELIX-805] - Instance not created if the factory becomes valid later
+ * [FELIX-866] - iPOJO Provides 'interface' attribute should be 'specifications'
+
+** Improvement
+ * [FELIX-787] - iPOJO logger log messages inside the log service and print them
+ * [FELIX-796] - Allows enabling/disabling the internal event dispatcher
+ * [FELIX-801] - Support service properties injection in bind/unbind callbacks
+ * [FELIX-815] - Support optional properties
+ * [FELIX-816] - Support comparator attribute with any service binding policy
+ * [FELIX-818] - Implement the ServiceReference compareTo method
+ * [FELIX-853] - Provide new service object creation strategies
+ * New introspection API
+
+Changes from 0.8.0 to 1.0.0
+---------------------------
+** Bug
+ * [FELIX-557] - Factories still living when a primitive component does not have its manipulation metadata
+ * [FELIX-632] - Component are set to immediate despite they are already immediate
+ * [FELIX-635] - Simplify factory name computation
+ * [FELIX-628] - Architecture service should not publish the instance.name property
+ * [FELIX-621] - Instances not disposed when instances creation failed
+
+** Improvement
+ * [FELIX-552] - ClassCastException when using services as dynamic proxies
+ * [FELIX-555] - Error message in the iPOJO Extender could be more accurate when failing to get the bundle context
+ * [FELIX-558] - Non caught NoClassDefFoundError when the instantiation of a Nullable object failed
+ * [FELIX-603] - Improve iPOJO Arch service dependency description
+ * [FELIX-626] - Allow specifying instance configuration containing empty dictionaries
+ * [FELIX-629] - Allows instance configuration to declares complex properties
+ * [FELIX-631] - Immediate Component Detection
+ * [FELIX-633] - Factory creation should be done in another thread
+ * [FELIX-634] - Improve error handling
+ * [FELIX-655] - Add a 'from' attribute in the service dependencies
+ * [FELIX-673] - Provide OBR description to iPOJO bundles
+ * [FELIX-683] - Supporting lists and vectors in the service dependency management
+ * [FELIX-686] - Supporting collections and set in the service dependency management
+ * [FELIX-688] - Better error reporting when an instance creation failed
+ * [FELIX-689] - Instance 'name' property should become 'instance.name'
+ * [FELIX-716] - Provide XML schemas for iPOJO descriptors
+ * [FELIX-732] - Duplicate instance created of a managed service
+
+Version 0.8.0
+-------------
+ * Initial release
diff --git a/ipojo/runtime/karaf-feature/pom.xml b/ipojo/runtime/karaf-feature/pom.xml
new file mode 100644
index 0000000..9348778
--- /dev/null
+++ b/ipojo/runtime/karaf-feature/pom.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>org.apache.felix.ipojo.features</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+
+ <name>Apache Felix iPOJO Karaf Features</name>
+ <description>Apache Karaf Features to provision Apache Felix iPOJO</description>
+
+ <packaging>pom</packaging>
+
+ <properties>
+ <ipojo.webconsole.version>1.7.0</ipojo.webconsole.version>
+ <legal.files>${project.build.directory}/maven-shared-archive-resources/META-INF</legal.files>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/features</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/features.xml</file>
+ <type>xml</type>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <attach>true</attach>
+ </configuration>
+ <executions>
+ <execution>
+ <id>build-archive</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>ianal-maven-plugin</artifactId>
+ <version>1.0-alpha-1</version>
+ <configuration>
+ <!-- the zip structure is not compatible with the ianal check, skip it -->
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/karaf-feature/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/karaf-feature/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..05c68c0
--- /dev/null
+++ b/ipojo/runtime/karaf-feature/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,10 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+II. Used Third-Party Software
+
+III. Overall License Summary
+- Apache License 2.0
diff --git a/ipojo/runtime/karaf-feature/src/main/assembly/assembly.xml b/ipojo/runtime/karaf-feature/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..3fb95b8
--- /dev/null
+++ b/ipojo/runtime/karaf-feature/src/main/assembly/assembly.xml
@@ -0,0 +1,54 @@
+<!--
+ ~ 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.
+ -->
+
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>feature</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>/</baseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}</directory>
+ <includes>
+ <include>features.xml</include>
+ </includes>
+ <outputDirectory/>
+ </fileSet>
+
+ <fileSet>
+ <directory>${project.basedir}</directory>
+ <includes>
+ <include>changelog.txt</include>
+ </includes>
+ <outputDirectory/>
+ </fileSet>
+
+ <fileSet>
+ <directory>${legal.files}</directory>
+ <outputDirectory/>
+ </fileSet>
+ </fileSets>
+</assembly>
\ No newline at end of file
diff --git a/ipojo/runtime/karaf-feature/src/main/features/features.xml b/ipojo/runtime/karaf-feature/src/main/features/features.xml
new file mode 100644
index 0000000..41f51d0
--- /dev/null
+++ b/ipojo/runtime/karaf-feature/src/main/features/features.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="${project.artifactId}">
+
+ <feature name="ipojo" version="${project.version}"
+ description="Apache Felix iPOJO Core Runtime">
+ <bundle>mvn:${project.groupId}/org.apache.felix.ipojo/${project.version}</bundle>
+ </feature>
+
+ <feature name="ipojo-command" version="${project.version}"
+ description="Apache Felix iPOJO Shell Command">
+ <feature version="${project.version}">ipojo</feature>
+ <bundle>mvn:${project.groupId}/org.apache.felix.ipojo.gogo/${project.version}</bundle>
+ </feature>
+
+ <feature name="ipojo-all" version="${project.version}"
+ description="Apache Felix iPOJO All Runtime Bundles">
+ <feature version="${project.version}">ipojo-command</feature>
+ <bundle>mvn:${project.groupId}/org.apache.felix.ipojo.composite/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/org.apache.felix.ipojo.api/${project.version}</bundle>
+ </feature>
+
+ <feature name="ipojo-webconsole" version="${project.version}"
+ description="Apache Felix iPOJO Web Console Plugin">
+ <feature version="${project.version}">ipojo</feature>
+ <feature>webconsole</feature>
+ <bundle>mvn:${project.groupId}/org.apache.felix.ipojo.webconsole/${ipojo.webconsole.version}</bundle>
+ </feature>
+</features>
\ No newline at end of file
diff --git a/ipojo/runtime/pom.xml b/ipojo/runtime/pom.xml
new file mode 100644
index 0000000..29b2722
--- /dev/null
+++ b/ipojo/runtime/pom.xml
@@ -0,0 +1,81 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.apache.felix.ipojo.runtime-project</artifactId>
+ <version>1.12.2-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Runtime Project</name>
+ <packaging>pom</packaging>
+
+ <description>
+ The iPOJO runtime project contains the core iPOJO bundle, the composite support and the api.
+ </description>
+
+ <modules>
+ <module>core</module>
+ <module>api</module>
+ <module>composite</module>
+ <module>core-it</module>
+ <module>composite-it</module>
+ <module>ipojo-gogo-commands</module>
+ <module>karaf-feature</module>
+ </modules>
+
+ <profiles>
+ <profile>
+ <id>distributions</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <modules>
+ <module>distributions/quickstart</module>
+ <module>distributions/ten-minutes-tutorial</module>
+ <module>distributions/maven-tutorial</module>
+ </modules>
+ </profile>
+ </profiles>
+
+ <scm>
+ <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
+ <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <tagBase>https://svn.apache.org/repos/asf/felix/releases</tagBase>
+ <useReleaseProfile>false</useReleaseProfile>
+ <goals>deploy</goals>
+ <arguments>-Papache-release</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ipojo/runtime/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/runtime/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..844c77e
--- /dev/null
+++ b/ipojo/runtime/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,21 @@
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/runtime/src/main/appended-resources/META-INF/NOTICE b/ipojo/runtime/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..4ae983c
--- /dev/null
+++ b/ipojo/runtime/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,8 @@
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/webconsole-plugin/changelog.txt b/ipojo/webconsole-plugin/changelog.txt
new file mode 100644
index 0000000..051a8dc
--- /dev/null
+++ b/ipojo/webconsole-plugin/changelog.txt
@@ -0,0 +1,37 @@
+Changes from the 1.6.0 to the 1.7.0
+-----------------------------------
+** Improvements
+ * Remove dependency to org.json
+
+
+Changes from the 1.6.0 to the 1.7.0
+-----------------------------------
+** Improvements
+ * Integration with the webconsole 4.x
+
+** Task
+ * [FELIX-3921] - Update pom to latest Felix's parent
+
+Changes from the 1.4.4 to 1.6.0
+-------------------------------
+** Improvements
+ * Integration with the webconsole 3.x
+
+Changes from the 1.4.2 to 1.4.4
+-------------------------------
+** Bug
+ * [FELIX-1579] - iPOJO Web Console Plugin 1.4.2 does not work as expected
+
+Changes from the 1.4.0 to 1.4.2
+-------------------------------
+** Bug
+ * [FELIX-1497] - iPOJO Web Console plugin NPE when the service reference list is null
+
+
+Version 1.4.0
+-------------
+** Improvement
+ * Update parent pom
+ * Initial commit
+
+
diff --git a/ipojo/webconsole-plugin/obr.xml b/ipojo/webconsole-plugin/obr.xml
new file mode 100644
index 0000000..59518cc
--- /dev/null
+++ b/ipojo/webconsole-plugin/obr.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<obr>
+ <capability name="service">
+ <p n="service" v="javax.servlet.Servlet" />
+ <p n="felix.webconsole.label"
+ v="iPOJO" />
+ <p n="felix.webconsole.title"
+ v="iPOJO" />
+ <p n="service.vendor" v="The Apache Software Foundation" />
+ </capability>
+</obr>
diff --git a/ipojo/webconsole-plugin/pom.xml b/ipojo/webconsole-plugin/pom.xml
new file mode 100644
index 0000000..fc11f1d
--- /dev/null
+++ b/ipojo/webconsole-plugin/pom.xml
@@ -0,0 +1,133 @@
+<!--
+ 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <artifactId>org.apache.felix.ipojo.webconsole</artifactId>
+ <version>1.7.1-SNAPSHOT</version>
+ <name>Apache Felix iPOJO WebConsole Plugins</name>
+
+ <description>
+ iPOJO plugin for the Apache Felix Web Console. This plugin allows introspecting an iPOJO system with the Apache
+ Felix
+ Web Console.
+ </description>
+ <url>http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-webconsole-plugin.html</url>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-DocURL>
+ http://felix.apache.org/documentation/subprojects/apache-felix-ipojo/apache-felix-ipojo-tools/ipojo-webconsole-plugin.html
+ </Bundle-DocURL>
+ <Private-Package>
+ org.apache.felix.ipojo.webconsole
+ </Private-Package>
+ <Import-Package>*</Import-Package>
+ <Embed-Dependency>
+ org.apache.felix.utils;inline=org/apache/felix/utils/json/JSONWriter**
+ </Embed-Dependency>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.8.6</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <enableRulesSummary>false</enableRulesSummary>
+ <violationSeverity>warning</violationSeverity>
+ <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <version>4.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.11.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.11.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.3</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ <version>1.9.0</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <scm>
+ <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
+ <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+ </scm>
+</project>
diff --git a/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/DEPENDENCIES b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
new file mode 100644
index 0000000..1735c8e
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/DEPENDENCIES
@@ -0,0 +1,17 @@
+I. Included Third-Party Software
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+Licensed under the JSON License
+
+II. Used Third-Party Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2009).
+Licensed under the Apache License 2.0.
+
+III. Overall License Summary
+- Apache License 2.0
+- JSON License
+
diff --git a/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/LICENSE b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..9bf7bd2
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,33 @@
+
+
+APACHE FELIX iPOJO Web Console plugin:
+
+The Apache Felix iPOJO Web Console Plugin includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+
+For the JSON component:
+
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/NOTICE b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..2c62a34
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,4 @@
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+Licensed under the JSON License
+
diff --git a/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java
new file mode 100644
index 0000000..7fa7399
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/IPOJOPlugin.java
@@ -0,0 +1,821 @@
+/*
+ * 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.webconsole;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandlerDescription;
+import org.apache.felix.utils.json.JSONWriter;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.WebConsoleUtil;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * iPOJO Web Console plugin.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings("serial")
+@Component(immediate=true)
+@Provides
+@Instantiate
+public class IPOJOPlugin extends AbstractWebConsolePlugin {
+
+ /**
+ * Used CSS files.
+ */
+ private static final String CSS[] = { "/res/ui/bundles.css" , "/iPOJO/res/ui/ipojo.css" };
+
+ /**
+ * Template : Instance list.
+ */
+ private final String INSTANCES;
+
+ /**
+ * Template : Factory list.
+ */
+ private final String FACTORIES;
+
+ /**
+ * Template : Handler list.
+ */
+ private final String HANDLERS;
+
+ /**
+ * Template : Factory details.
+ */
+ private final String FACTORY_DETAILS;
+
+ /**
+ * Template : Instance details.
+ */
+ private final String INSTANCE_DETAILS;
+
+ /**
+ * Label used by the web console.
+ */
+ @ServiceProperty(name = "felix.webconsole.label")
+ private String m_label = "iPOJO";
+
+ /**
+ * Title used by the web console.
+ */
+ @ServiceProperty(name = "felix.webconsole.title")
+ private String m_title = "iPOJO";
+
+ /**
+ * CSS files used by the plugin.
+ */
+ @ServiceProperty(name= "felix.webconsole.css")
+ protected String[] m_css = CSS;
+
+ /**
+ * List of available Architecture service.
+ */
+ @Requires(optional = true, specification = Architecture.class)
+ private List<Architecture> m_archs;
+
+ /**
+ * List of available Factories.
+ */
+ @Requires(optional = true, specification = Factory.class)
+ private List<Factory> m_factories;
+
+ /**
+ * List of available Handler Factories.
+ */
+ @Requires(optional = true, specification = HandlerFactory.class)
+ private List<HandlerFactory> m_handlers;
+
+ /**
+ * Instantiates the plugin.
+ * This method loads all template files.
+ */
+ public IPOJOPlugin() {
+ INSTANCES = readTemplate("/res/instances.html" );
+ FACTORIES = readTemplate("/res/factories.html" );
+ HANDLERS = readTemplate("/res/handlers.html" );
+ FACTORY_DETAILS = readTemplate("/res/factory.html" );
+ INSTANCE_DETAILS = readTemplate("/res/instance.html" );
+ }
+
+ /**
+ * Helper method loading a template file.
+ * @param templateFile the template file name
+ * @return the template
+ */
+ private String readTemplate(final String templateFile) {
+ InputStream templateStream = getClass().getResourceAsStream(
+ templateFile);
+ if (templateStream != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] data = new byte[1024];
+ try {
+ int len = 0;
+ while ((len = templateStream.read(data)) > 0) {
+ baos.write(data, 0, len);
+ }
+ return baos.toString("UTF-8");
+ } catch (IOException e) {
+ // don't use new Exception(message, cause) because cause is 1.4+
+ throw new RuntimeException("readTemplateFile: Error loading "
+ + templateFile + ": " + e);
+ } finally {
+ try {
+ templateStream.close();
+ } catch (IOException e) {
+ /* ignore */
+ }
+
+ }
+ }
+
+ // template file does not exist, return an empty string
+ log("readTemplateFile: File '" + templateFile
+ + "' not found through class " + this.getClass());
+ return "";
+ }
+
+ /**
+ * This methods is called by the web console when the plugin is required.
+ * This methods writes the corresponding page (loads template and set variables).
+ * @param request the request
+ * @param response the response
+ * @throws ServletException something bad happened
+ * @throws IOException something bad happened
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(
+ * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void renderContent(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ // get request info from request attribute
+ final RequestInfo reqInfo = new RequestInfo(request);
+ // prepare variables
+ DefaultVariableResolver vars = ( ( DefaultVariableResolver ) WebConsoleUtil.getVariableResolver( request ) );
+
+ if (reqInfo.instances) { // Instance
+ if (reqInfo.name == null) { // All
+ response.getWriter().print( INSTANCES );
+ } else { // Specific
+ vars.put("name", reqInfo.name); // Inject the name variable.
+ response.getWriter().print( INSTANCE_DETAILS );
+ }
+ } else if (reqInfo.factories) { // Factory
+ if (reqInfo.name == null) { // All
+ response.getWriter().print( FACTORIES );
+ } else { // Specific
+ vars.put("name", reqInfo.name); // Inject the name variable.
+ response.getWriter().print( FACTORY_DETAILS );
+ }
+ } else if (reqInfo.handlers) { // Handlers
+ response.getWriter().print( HANDLERS );
+ // No detailed view for handlers.
+ } else {
+ // Default
+ response.getWriter().print( INSTANCES );
+ }
+ }
+
+ /**
+ * Writes the JSON object containing the info for all instances.
+ * @param pw the writer where the json object is printed.
+ * @throws IOException the JSON object cannot be written
+ */
+ private void getAllInstances(JSONWriter pw) throws IOException {
+ pw.object();
+ // Statline:
+ pw.key("count");
+ pw.value( m_archs.size());
+ pw.key("valid_count");
+ pw.value( StateUtils.getValidInstancesCount(m_archs));
+ pw.key("invalid_count");
+ pw.value( StateUtils.getInvalidInstancesCount(m_archs));
+ // End statline
+
+ pw.key("data");
+ pw.array();
+ for (Architecture arch : m_archs) {
+ pw.object();
+ pw.key("name");
+ pw.value(arch.getInstanceDescription().getName());
+ pw.key("factory");
+ pw.value(arch.getInstanceDescription().getComponentDescription().getName());
+ pw.key("state");
+ pw.value(StateUtils.getInstanceState(arch.getInstanceDescription().getState()));
+ pw.endObject();
+ }
+ pw.endArray();
+
+ pw.endObject();
+ }
+
+ /**
+ * Writes the JSON object containing the info for all factories.
+ * @param pw the writer when the json object is printed
+ * @throws IOException the JSON object cannot be written
+ */
+ private void getAllFactories(JSONWriter pw) throws IOException {
+ pw.object();
+ // Statline:
+ pw.key("count");
+ pw.value(m_factories.size());
+ pw.key("valid_count");
+ pw.value(StateUtils.getValidFactoriesCount(m_factories));
+ pw.key("invalid_count");
+ pw.value(StateUtils.getInvalidFactoriesCount(m_factories));
+ // End statline
+
+ pw.key("data");
+ pw.array();
+ for (Factory factory : m_factories) {
+ String version = factory.getVersion();
+ String name = factory.getName();
+
+ String state = StateUtils.getFactoryState(factory.getState());
+ String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ + " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
+ pw.object();
+ pw.key("name");
+ pw.value(name);
+ if (version != null) {
+ pw.key("version");
+ pw.value(version);
+ }
+ pw.key("bundle");
+ pw.value(bundle);
+ pw.key("state");
+ pw.value(state);
+ pw.endObject();
+ }
+ pw.endArray();
+
+ pw.endObject();
+ }
+
+ /**
+ * Writes the JSON object containing the info for all handlers.
+ * @param pw the writer when the json object is printed
+ * @throws IOException the JSON object cannot be written
+ */
+ private void getAllHandlers(JSONWriter pw) throws IOException {
+ pw.object();
+
+ // Statline:
+ pw.key("count");
+ pw.value(m_handlers.size());
+ pw.key("valid_count");
+ pw.value(StateUtils.getValidHandlersCount(m_handlers));
+ pw.key("invalid_count");
+ pw.value(StateUtils.getInvalidHandlersCount(m_handlers));
+ // End statline
+
+ pw.key("data");
+ pw.array();
+ for (HandlerFactory factory : m_handlers) {
+ String version = factory.getVersion();
+ String name = factory.getHandlerName();
+
+ String state = StateUtils.getFactoryState(factory.getState());
+ String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ + " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
+ pw.object();
+ pw.key("name");
+ pw.value( name);
+ if (version != null) {
+ pw.key("version");
+ pw.value(version);
+ }
+ pw.key("bundle");
+ pw.value(bundle);
+ pw.key("state");
+ pw.value(state);
+ pw.key("type");
+ pw.value(factory.getType());
+ if (! factory.getMissingHandlers().isEmpty()) {
+ pw.key("missing");
+ pw.value(factory.getMissingHandlers().toString());
+ }
+ pw.endObject();
+ }
+ pw.endArray();
+ pw.endObject();
+ }
+
+ /**
+ * Writes the JSON object containing details about a specific factory.
+ * @param pw the writer
+ * @param name the factory name
+ * @throws IOException if the json object cannot be written.
+ */
+ private void getFactoryDetail(JSONWriter pw, String name) throws IOException{
+ // Find the factory
+ Factory factory = null;
+ for (Factory fact : m_factories) {
+ if (fact.getName().equals(name)) {
+ factory = fact;
+ }
+ }
+
+ if (factory == null) {
+ // This will be used a error message (cannot be interpreted as json)
+ pw.value("The factory " + name + " does not exist or is private");
+ return;
+ }
+
+ pw.object();
+
+ // Statline.
+ pw.key("count");
+ pw.value(m_factories.size());
+ pw.key("valid_count");
+ pw.value(StateUtils.getValidFactoriesCount(m_factories));
+ pw.key("invalid_count");
+ pw.value(StateUtils.getInvalidFactoriesCount(m_factories));
+ // End of the statline
+
+ // Factory object
+ pw.key("data");
+ pw.object();
+ pw.key("name");
+ pw.value(factory.getName());
+ pw.key("state");
+ pw.value(StateUtils.getFactoryState(factory.getState()));
+
+ String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ + " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
+ pw.key("bundle");
+ pw.value(bundle);
+
+ // Provided service specifications
+ if (factory.getComponentDescription().getprovidedServiceSpecification().length != 0) {
+ pw.key("services");
+ pw.value(factory.getComponentDescription().getprovidedServiceSpecification());
+ }
+
+ // Properties
+ PropertyDescription[] props = factory.getComponentDescription().getProperties();
+ if (props != null && props.length != 0) {
+ pw.key("properties");
+ pw.array();
+ for (int i = 0; i < props.length; i++) {
+ pw.object();
+ pw.key("name");
+ pw.value(props[i].getName());
+ pw.key("type");
+ pw.value(props[i].getType());
+ pw.key("mandatory");
+ pw.value(props[i].isMandatory());
+ pw.key("immutable");
+ pw.value(props[i].isImmutable());
+ if (props[i].getValue() != null) {
+ pw.key("value");
+ pw.value(props[i].getValue());
+ }
+ pw.endObject();
+ }
+ pw.key("properties");
+ pw.array();
+ pw.endArray();
+ }
+
+ if (! factory.getRequiredHandlers().isEmpty()) {
+ pw.key("requiredHandlers");
+ pw.value(factory.getRequiredHandlers());
+ }
+
+ if (! factory.getMissingHandlers().isEmpty()) {
+ pw.key("missingHandlers");
+ pw.value(factory.getMissingHandlers());
+ }
+
+ List<?> instances = StateUtils.getInstanceList(m_archs, name);
+ if (! instances.isEmpty()) {
+ pw.key("instances");
+ pw.value(instances);
+ }
+
+ pw.key("architecture");
+ pw.value(factory.getDescription().toString());
+ pw.endObject();
+ pw.endObject();
+ }
+
+ /**
+ * Writes the JSON object containing details about a specific instance.
+ * @param pw the writer
+ * @param name the instance name
+ * @throws IOException if the json object cannot be written.
+ */
+ private void getInstanceDetail(JSONWriter pw, String name) throws IOException {
+ // Find the factory
+ InstanceDescription instance = null;
+ for (Architecture arch : m_archs) {
+ if (arch.getInstanceDescription().getName().equals(name)) {
+ instance = arch.getInstanceDescription();
+ }
+ }
+
+ if (instance == null) {
+ // This will be used a error message (cannot be interpreted as json)
+ pw.value("The instance " + name + " does not exist or " +
+ "does not exposed its architecture");
+ return;
+ }
+
+ pw.object();
+
+ pw.key("count");
+ pw.value(m_factories.size());
+ pw.key("valid_count");
+ pw.value(StateUtils.getValidFactoriesCount(m_factories));
+ pw.key("invalid_count");
+ pw.value(StateUtils.getInvalidFactoriesCount(m_factories));
+
+ // instance object
+ pw.key("data");
+ pw.object();
+ pw.key("name");
+ pw.value(instance.getName());
+ pw.key("state");
+ pw.value(StateUtils.getInstanceState(instance.getState()));
+ pw.key("factory");
+ pw.value(instance.getComponentDescription().getName());
+
+ getProvidedServiceDetail(pw, instance.getHandlerDescription("org.apache.felix.ipojo:provides"));
+
+ getRequiredServiceDetail(pw, instance.getHandlerDescription("org.apache.felix.ipojo:requires"));
+
+ pw.key("architecture");
+ pw.value(instance.getDescription().toString());
+
+ pw.endObject();
+ pw.endObject();
+ }
+
+ /**
+ * Endpoint dealing with JSON requests.
+ * @param request the request
+ * @param response the response
+ * @throws ServletException if an error occurred
+ * @throws IOException if an error occurred
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#doGet
+ * (javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ final RequestInfo reqInfo = new RequestInfo(request);
+
+ if (reqInfo.extension.equals("json")) {
+ response.setContentType("application/json");
+ final JSONWriter writer = new JSONWriter(response.getWriter());
+ if (reqInfo.instances) {
+ if (reqInfo.name == null) {
+ this.getAllInstances(writer);
+ writer.flush();
+ return;
+ } else {
+ this.getInstanceDetail(writer, reqInfo.name);
+ writer.flush();
+ return;
+ }
+ }
+
+ if (reqInfo.factories) {
+ if (reqInfo.name == null) {
+ this.getAllFactories(writer);
+ writer.flush();
+ return;
+ } else {
+ this.getFactoryDetail(writer, reqInfo.name);
+ writer.flush();
+ return;
+ }
+ }
+
+ if (reqInfo.handlers) {
+ this.getAllHandlers(writer);
+ }
+ // nothing more to do
+ writer.flush();
+ return;
+ }
+ // Otherwise, delegate to super.
+ super.doGet(request, response);
+ }
+
+ /**
+ * Allows loading the 'ui' folder as web resource.
+ * @param path the resource path
+ * @return the internal resource url.
+ */
+ public URL getResource(String path) {
+ if (path.contains("/res/ui/")) {
+ return this.getClass().getResource(
+ path.substring(m_label.length() + 1));
+ }
+ return null;
+ }
+
+ /**
+ * Creates the JSON Array describing the provided services.
+ * @param hd the provided service handler
+ * @return the JSON Array or null if no provided service
+ * @throws JSONException if the array cannot be created.
+ */
+ private void getProvidedServiceDetail(final JSONWriter pw, HandlerDescription hd) throws IOException {
+ if (hd == null) {
+ return;
+ }
+
+ pw.key("services");
+ pw.array();
+ ProvidedServiceHandlerDescription desc = (ProvidedServiceHandlerDescription) hd;
+
+ for (ProvidedServiceDescription ps : desc.getProvidedServices()) {
+ pw.object();
+ String spec = Arrays.toString(ps.getServiceSpecifications());
+ if (spec.startsWith("[")) {
+ spec = spec.substring(1, spec.length() - 1);
+ }
+ pw.key("specification");
+ pw.value(spec);
+ pw.key("state");
+ pw.value(StateUtils.getProvidedServiceState(ps.getState()));
+
+ if (ps.getServiceReference() != null) {
+ pw.key("id");
+ pw.value(ps.getServiceReference().getProperty(Constants.SERVICE_ID));
+ }
+
+ if (ps.getProperties() != null && !ps.getProperties().isEmpty()) {
+ pw.key("properties");
+ getServiceProperties(pw, ps.getProperties());
+ }
+
+ pw.endObject();
+ }
+ pw.endArray();
+ }
+
+ /**
+ * Builds the JSON Array containing object representing the given properties
+ * (name / value pair).
+ * @param properties the properties
+ * @return the JSON Array
+ * @throws JSONException if the array cannot be created correctly
+ */
+ private void getServiceProperties(JSONWriter pw, Properties properties) throws IOException {
+ pw.array();
+ Enumeration<Object> e = properties.keys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ Object value = properties.get(key);
+ pw.object();
+ pw.key("name");
+ pw.value(key);
+ if (value != null && value.getClass().isArray()) {
+ // TODO Test with primitive types
+ pw.key("value");
+ pw.value(Arrays.toString((Object[]) value));
+ } else if (value != null) {
+ pw.key("value");
+ pw.value(value.toString());
+ } else {
+ pw.key("value");
+ pw.value("no value");
+ }
+ pw.endObject();
+ }
+ pw.endArray();
+ }
+
+ /**
+ * Builds the JSON Array representing the required services.
+ * @param hd the dependency handler
+ * @return the array containing JSON object representing service
+ * dependencies, or null if there is no service dependency.
+ * @throws JSONException if the JSON array cannot be created.
+ */
+ private void getRequiredServiceDetail(JSONWriter pw,
+ HandlerDescription hd) throws IOException {
+ if (hd == null) {
+ return;
+ }
+ pw.key("reqs");
+ pw.array();
+ DependencyHandlerDescription desc = (DependencyHandlerDescription) hd;
+ for (DependencyDescription dep : desc.getDependencies()) {
+ pw.object();
+ pw.key("specification");
+ pw.value(dep.getSpecification());
+ pw.key("id");
+ pw.value(dep.getId());
+ pw.key("state");
+ pw.value(StateUtils.getDependencyState(dep.getState()));
+ pw.key("policy");
+ pw.value(StateUtils.getDependencyBindingPolicy(dep.getPolicy()));
+ pw.key("optional");
+ pw.value(dep.isOptional());
+ pw.key("aggregate");
+ pw.value(dep.isMultiple());
+ if (dep.getFilter() != null) {
+ pw.key("filter");
+ pw.value(dep.getFilter());
+ }
+ if (dep.getServiceReferences() != null && dep.getServiceReferences().size() != 0) {
+ pw.key("matching");
+ getServiceReferenceList(pw, dep.getServiceReferences());
+ }
+
+ if (dep.getUsedServices() != null && dep.getUsedServices().size() != 0) {
+ pw.key("used");
+ getServiceReferenceList(pw, dep.getUsedServices());
+ }
+
+ pw.endObject();
+ }
+
+ pw.endArray();
+ }
+
+ /**
+ * Builds the JSON Array representing the given service reference list.
+ * The array contains JSON objects. Those object contains the service id (id)
+ * as well as the instance name (instance) if the property is set in the service
+ * reference.
+ * @param refs the service reference list
+ * @return the JSON Array
+ * @throws JSONException if the array cannot be created.
+ */
+ private void getServiceReferenceList(JSONWriter pw, List<ServiceReference> refs) throws IOException {
+ pw.array();
+ if (refs != null) {
+ for (ServiceReference ref : refs) {
+ pw.object();
+ if (ref.getProperty("instance.name") == null) {
+ pw.key("id");
+ pw.value(ref.getProperty(Constants.SERVICE_ID));
+ } else {
+ pw.key("id");
+ pw.value(ref.getProperty(Constants.SERVICE_ID));
+ pw.key("instance");
+ pw.value(ref.getProperty("instance.name"));
+ }
+ pw.endObject();
+ }
+ }
+ pw.endArray();
+ }
+
+ /**
+ * Gets the plugin label.
+ * @return the label.
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getLabel()
+ */
+ @Override
+ public String getLabel() {
+ return m_label;
+ }
+
+ /**
+ * Gets the plugin title.
+ * @return the title
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getTitle()
+ */
+ @Override
+ public String getTitle() {
+ return m_title;
+ }
+
+ /**
+ * Get the CSS used by the plugin.
+ * @return the list of CSS
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getCssReferences()
+ */
+ @Override
+ protected String[] getCssReferences() {
+ return CSS;
+ }
+
+
+
+ /**
+ * Parse request to extract the query.
+ */
+ private final class RequestInfo {
+ /**
+ * The extension.
+ */
+ public final String extension;
+ /**
+ * The path.
+ */
+ public final String path;
+ /**
+ * The instances.
+ */
+ public final boolean instances;
+ /**
+ * The factories.
+ */
+ public final boolean factories;
+ /**
+ * The handlers.
+ */
+ public final boolean handlers;
+
+ /**
+ * The specific factory or instance name.
+ */
+ public final String name;
+
+
+ /**
+ * Creates a RequestInfo.
+ * @param request the request
+ */
+ protected RequestInfo( final HttpServletRequest request ) {
+ String info = request.getPathInfo();
+ // remove label and starting slash
+ info = info.substring(getLabel().length() + 1);
+
+ // get extension
+ if (info.endsWith(".json")) {
+ extension = "json";
+ info = info.substring(0, info.length() - 5);
+ } else {
+ extension = "html";
+ }
+
+ if (info.startsWith("/")) {
+ path = info.substring(1);
+
+ instances = path.startsWith("instances");
+ factories = path.startsWith("factories");
+ handlers = path.startsWith("handlers");
+
+ if (instances && path.startsWith("instances/")) {
+ name = path.substring("instances".length() + 1);
+ } else if (factories && path.startsWith("factories/")) {
+ name = path.substring("factories".length() + 1);
+ } else {
+ name = null;
+ }
+ } else {
+ path = null;
+ name = null;
+ instances = false;
+ factories = false;
+ handlers = false;
+ }
+
+ request.setAttribute(IPOJOPlugin.class.getName(), this);
+ }
+
+ }
+
+}
diff --git a/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/StateUtils.java b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/StateUtils.java
new file mode 100644
index 0000000..c4eec56
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/java/org/apache/felix/ipojo/webconsole/StateUtils.java
@@ -0,0 +1,233 @@
+/*
+ * 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.webconsole;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService;
+import org.apache.felix.ipojo.util.DependencyModel;
+
+
+/**
+ * Helper class dealing with instance and factory states.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StateUtils {
+
+ /**
+ * Gets the number of valid instances.
+ * @param archs the instance architecture list
+ * @return the number of valid instances.
+ */
+ public static int getValidInstancesCount(List<Architecture> archs) {
+ int i = 0;
+ for (Architecture a : archs) { // Cannot be null, an empty list is returned.
+ if (a.getInstanceDescription().getState() == ComponentInstance.VALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the number of invalid instances.
+ * @param archs the instance architecture list
+ * @return the number of invalid instances.
+ */
+ public static int getInvalidInstancesCount(List<Architecture> archs) {
+ int i = 0;
+ for (Architecture a : archs) { // Cannot be null, an empty list is returned.
+ if (a.getInstanceDescription().getState() == ComponentInstance.INVALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the number of valid factories.
+ * @param factories the factory list
+ * @return the number of valid factories.
+ */
+ public static int getValidFactoriesCount(List<Factory> factories) {
+ int i = 0;
+ for (Factory a : factories) { // Cannot be null, an empty list is returned.
+ if (a.getState() == Factory.VALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the number of invalid factories.
+ * @param factories the factory list
+ * @return the number of invalid factories.
+ */
+ public static int getInvalidFactoriesCount(List<Factory> factories) {
+ int i = 0;
+ for (Factory a : factories) { // Cannot be null, an empty list is returned.
+ if (a.getState() == Factory.INVALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the number of valid handlers.
+ * @param handlers the handler factory list
+ * @return the number of valid handlers.
+ */
+ public static int getValidHandlersCount(List<HandlerFactory> handlers) {
+ int i = 0;
+ for (Factory a : handlers) { // Cannot be null, an empty list is returned.
+ if (a.getState() == Factory.VALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the number of invalid handlers.
+ * @param handlers the handler factory list
+ * @return the number of invalid handlers.
+ */
+ public static int getInvalidHandlersCount(List<HandlerFactory> handlers) {
+ int i = 0;
+ for (Factory a : handlers) { // Cannot be null, an empty list is returned.
+ if (a.getState() == Factory.INVALID) {
+ i ++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Gets the instance state as a String.
+ * @param state the state.
+ * @return the String form of the state.
+ */
+ public static String getInstanceState(int state) {
+ switch(state) {
+ case ComponentInstance.VALID :
+ return "valid";
+ case ComponentInstance.INVALID :
+ return "invalid";
+ case ComponentInstance.DISPOSED :
+ return "disposed";
+ case ComponentInstance.STOPPED :
+ return "stopped";
+ default :
+ return "unknown";
+ }
+ }
+
+ /**
+ * Gets the factory state as a String.
+ * @param state the state.
+ * @return the String form of the state.
+ */
+ public static String getFactoryState(int state) {
+ switch(state) {
+ case Factory.VALID :
+ return "valid";
+ case Factory.INVALID :
+ return "invalid";
+ default :
+ return "unknown";
+ }
+ }
+
+ /**
+ * Gets the instance list created by the given factory.
+ * @param archs the list of instance architectures
+ * @param factory the factory name
+ * @return the list containing the created instances (name)
+ */
+ public static List<String> getInstanceList(List<Architecture> archs, String factory) {
+ List<String> list = new ArrayList<String>();
+ for (Architecture arch : archs) { // Cannot be null, an empty list is returned.
+ String n = arch.getInstanceDescription().getComponentDescription().getName();
+ if (factory.equals(n)) {
+ list.add(arch.getInstanceDescription().getName());
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Gets the dependency state as a String.
+ * @param state the state.
+ * @return the String form of the state.
+ */
+ public static String getDependencyState(int state) {
+ switch(state) {
+ case DependencyModel.RESOLVED :
+ return "resolved";
+ case DependencyModel.UNRESOLVED :
+ return "unresolved";
+ case DependencyModel.BROKEN :
+ return "broken";
+ default :
+ return "unknown (" + state + ")";
+ }
+ }
+
+ /**
+ * Gets the dependency binding policy as a String.
+ * @param policy the policy.
+ * @return the String form of the policy.
+ */
+ public static String getDependencyBindingPolicy(int policy) {
+ switch(policy) {
+ case DependencyModel.DYNAMIC_BINDING_POLICY :
+ return "dynamic";
+ case DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY :
+ return "dynamic-priority";
+ case DependencyModel.STATIC_BINDING_POLICY :
+ return "static";
+ default :
+ return "unknown (" + policy + ")";
+ }
+ }
+
+ /**
+ * Gets the provided service state as a String.
+ * @param state the state.
+ * @return the String form of the state.
+ */
+ public static String getProvidedServiceState(int state) {
+ switch(state) {
+ case ProvidedService.REGISTERED :
+ return "registered";
+ case ProvidedService.UNREGISTERED :
+ return "unregistered";
+ default :
+ return "unknown (" + state + ")";
+ }
+ }
+
+}
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/factories.html b/ipojo/webconsole-plugin/src/main/resources/res/factories.html
new file mode 100644
index 0000000..060f99c
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/factories.html
@@ -0,0 +1,66 @@
+<!--
+ 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.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/ui/factory.js"></script>
+<script>
+ var root_url = '${pluginRoot}';
+ var instances_url = '${pluginRoot}' + '/instances';
+ var factories_url = '${pluginRoot}' + '/factories';
+ var handlers_url = '${pluginRoot}' + '/handlers';
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_Name">Factory Name</th>
+ <th class="col_Factory">Bundle</th>
+ <th class="col_State">State</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><!-- template -->
+ <td class="name"> </td>
+ <td class="bundle"> </td><!-- factory -->
+ <td class="state"> </td><!-- state -->
+ </tr>
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/factory.html b/ipojo/webconsole-plugin/src/main/resources/res/factory.html
new file mode 100644
index 0000000..a550989
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/factory.html
@@ -0,0 +1,114 @@
+<!--
+ 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.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/ui/factory_detail.js"></script>
+<script>
+ var root_url = '${pluginRoot}';
+ var instances_url = '${pluginRoot}' + '/instances';
+ var factories_url = '${pluginRoot}' + '/factories';
+ var handlers_url = '${pluginRoot}' + '/handlers';
+ var factory_name = '${name}';
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="nicetable noauto ui-widget-content">
+ <tbody>
+ <!-- template -->
+ <tr>
+ <td class="Nname lheader">Factory Name</td>
+ <td class="Vname"> </td>
+ </tr>
+ <tr>
+ <td class="Nstate lheader">State</td>
+ <td class="Vstate"> </td>
+ </tr>
+ <tr>
+ <td class="Nbundle lheader">Bundle</td>
+ <td class="Vbundle"> </td>
+ </tr>
+ <tr>
+ <td class="Nservices lheader">Provided Service Specifications</td>
+ <td class="Vservices"> </td>
+ </tr>
+ <tr>
+ <td class="Nproperties lheader">Configuration Properties</td>
+ <td class="Vproperties">
+ <table class="properties ui-widget-content">
+ <thead>
+ <tr>
+ <th class="col_Name">Name</th>
+ <th class="col_Type">Type</th>
+ <th class="col_Mandatory">Mandatory</th>
+ <th class="col_Immutable">Immutable</th>
+ <th class="col_Value">Default Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="ui-widget-content"><!-- template -->
+ <td class="ui-widget-content name"> </td>
+ <td class="ui-widget-content type"> </td>
+ <td class="ui-widget-content mandatory"> </td>
+ <td class="ui-widget-content immutable"> </td>
+ <td class="ui-widget-content value"> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="NrequiredHandlers lheader">Required Handlers</td>
+ <td class="VrequiredHandlers"> </td>
+ </tr>
+ <tr>
+ <td class="NmissingHandlers lheader">Missing Handlers</td>
+ <td class="VmissingHandlers"> </td>
+ </tr>
+ <tr>
+ <td class="NcreatedInstances lheader">Created Instances</td>
+ <td class="VcreatedInstances"> </td>
+ </tr>
+ <tr>
+ <td class="Narchitecture lheader">Architecture</td>
+ <td class="Varchitecture"><div class="architecture"><pre class="architecture_content"> </pre></div></td>
+ </tr>
+
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/handlers.html b/ipojo/webconsole-plugin/src/main/resources/res/handlers.html
new file mode 100644
index 0000000..caa08db
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/handlers.html
@@ -0,0 +1,70 @@
+<!--
+ 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.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/ui/handler.js"></script>
+<script>
+ var root_url = '${pluginRoot}';
+ var instances_url = '${pluginRoot}' + '/instances';
+ var factories_url = '${pluginRoot}' + '/factories';
+ var handlers_url = '${pluginRoot}' + '/handlers';
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_Name">Handler Name</th>
+ <th class="col_Type">Handler Type</th>
+ <th class="col_Bundle">Bundle</th>
+ <th class="col_State">State</th>
+ <th class="col_Missing">Missing Handlers</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><!-- template -->
+ <td class="name"> </td>
+ <td class="type"> </td>
+ <td class="bundle"> </td>
+ <td class="state"> </td>
+ <td class="missing"> </td>
+ </tr>
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/instance.html b/ipojo/webconsole-plugin/src/main/resources/res/instance.html
new file mode 100644
index 0000000..39a5b33
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/instance.html
@@ -0,0 +1,127 @@
+<!--
+ 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.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/ui/instance_detail.js"></script>
+<script>
+ var root_url = '${pluginRoot}';
+ var instances_url = '${pluginRoot}' + '/instances';
+ var factories_url = '${pluginRoot}' + '/factories';
+ var handlers_url = '${pluginRoot}' + '/handlers';
+ var instance_name = '${name}';
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="nicetable noauto ui-widget-content">
+ <tbody>
+ <!-- template -->
+ <tr>
+ <td class="Nname lheader">Instance Name</td>
+ <td class="Vname"> </td>
+ </tr>
+ <tr>
+ <td class="Nstate lheader">State</td>
+ <td class="Vstate"> </td>
+ </tr>
+ <tr>
+ <td class="Nfactory lheader">Factory</td>
+ <td class="Vfactory"> </td> <!-- TODO Link if possible -->
+ </tr>
+ <tr>
+ <td class="Nservices lheader">Provided Services</td>
+ <td class="Vservices">
+ <table class="services ui-widget-content">
+ <thead>
+ <tr>
+ <th class="col_Name">Specifications</th>
+ <th class="col_State">State</th>
+ <th class="col_Id">Service Id</th>
+ <th class="col_Properties">Service Properties</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="ui-widget-content"><!-- template -->
+ <td class="ui-widget-content name"> </td>
+ <td class="ui-widget-content state"> </td>
+ <td class="ui-widget-content id"> </td>
+ <td class="ui-widget-content properties"> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="NreqServices lheader">Required Services</td>
+ <td class="VreqServices">
+ <table class="reqServices ui-widget-content">
+ <thead>
+ <tr>
+ <th class="col_Name">Specification</th>
+ <th class="col_State">State</th>
+ <th class="col_Filter">Filter</th>
+ <th class="col_Policy">Binding Policy</th>
+ <th class="col_Optional">Optional</th>
+ <th class="col_Aggregate">Aggregate</th>
+ <th class="col_Matching">Matching Services</th>
+ <th class="col_Used">Used Services</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="ui-widget-content"><!-- template -->
+ <td class="ui-widget-content name"> </td>
+ <td class="ui-widget-content state"> </td>
+ <td class="ui-widget-content filter"> </td>
+ <td class="ui-widget-content policy"> </td>
+ <td class="ui-widget-content optional"> </td>
+ <td class="ui-widget-content aggregate"> </td>
+ <td class="ui-widget-content matching"> </td>
+ <td class="ui-widget-content used"> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="Narchitecture lheader">Architecture</td>
+ <td class="Varchitecture"><div class="architecture"><pre class="architecture_content"> </pre></div></td>
+ </tr>
+
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/instances.html b/ipojo/webconsole-plugin/src/main/resources/res/instances.html
new file mode 100644
index 0000000..8a61283
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/instances.html
@@ -0,0 +1,66 @@
+<!--
+ 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.
+-->
+<script type="text/javascript" src="${pluginRoot}/res/ui/ipojo.js"></script>
+<script>
+ var root_url = '${pluginRoot}';
+ var instances_url = '${pluginRoot}' + '/instances';
+ var factories_url = '${pluginRoot}' + '/factories';
+ var handlers_url = '${pluginRoot}' + '/handlers';
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_Name">Instance Name</th>
+ <th class="col_Factory">Factory</th>
+ <th class="col_State">State</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><!-- template -->
+ <td class="name"> </td>
+ <td class="factory"> </td><!-- factory -->
+ <td class="state"> </td><!-- state -->
+ </tr>
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <button class="instancesButton" type="button">Instances</button>
+ <button class="factoriesButton" type="button">Factories</button>
+ <button class="handlersButton" type="button">Handlers</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js
new file mode 100644
index 0000000..81fc782
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory.js
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+function renderFactoriesData(factories) {
+ $(".statline").html(getFactoriesStatLine(factories));
+ tableBody.empty();
+ for ( var idx in factories.data ) {
+ factoriesEntry( factories.data[idx] );
+ }
+ $("#plugin_table").trigger("update");
+}
+
+function getFactoriesStatLine(factories) {
+ return factories.count + " factories in total, "
+ + factories.valid_count + " valid factories, "
+ + factories.invalid_count + " invalid factories.";
+}
+
+function factoriesEntry(factory) {
+ var name = factory.name;
+ var state = factory.state;
+ var bundle = factory.bundle;
+
+ console.log("Create entry : " + factory);
+
+ var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'factory-' + factory.name);
+
+ _.find('td.name').html('<a href="' + factories_url + '/' + name + '">' + name + '</a>');
+ _.find('td.bundle').text(bundle);
+ _.find('td.state').text(state);
+}
+
+
+function loadFactoriesData() {
+ console.log("Load factories data");
+ $.get(pluginRoot + "/factories.json", null, function(data) {
+ renderFactoriesData(data);
+ }, "json");
+}
+
+function loadInstancesData() {
+ window.location = instances_url;
+}
+
+function loadHandlersData() {
+ window.location = handlers_url;
+}
+
+var tableBody = false;
+var tableEntryTemplate = false;
+
+$(document).ready(function(){
+ tableBody = $('#plugin_table tbody');
+ tableEntryTemplate = tableBody.find('tr').clone();
+
+ loadFactoriesData();
+
+ $(".instancesButton").click(loadInstancesData);
+ $(".factoriesButton").click(loadFactoriesData);
+ $(".handlersButton").click(loadHandlersData);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if ( link && link.length == 1 ) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+ $("#plugin_table").tablesorter({
+ sortList: [[1,0]],
+ textExtraction:extractMethod
+ });
+});
+
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/factory_detail.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory_detail.js
new file mode 100644
index 0000000..7af1c7c
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/factory_detail.js
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+function renderFactoryDetails(data) {
+ $(".statline").html(getFactoriesStatLine(data));
+ createDetail( data.data );
+ //$("#plugin_table").trigger("update");
+}
+
+function getFactoriesStatLine(factories) {
+ return factories.count + " factories in total, "
+ + factories.valid_count + " valid factories, "
+ + factories.invalid_count + " invalid factories.";
+}
+
+function createDetail(factory) {
+ console.log("Create details");
+ var name = factory.name;
+ var state = factory.state;
+ var bundle = factory.bundle;
+ var service = "No provided services"
+
+ console.log("Create entry : " + factory);
+
+ var _ = tableBody;
+
+ // Set the name
+ _.find('td.Vname').html(factory.name);
+ // Set the bundle //TODO we can create a link here ?
+ _.find('td.Vbundle').text(factory.bundle);
+ // Set the state
+ _.find('td.Vstate').text(factory.state);
+
+ // Set the services
+ // If define, use a list
+ if (factory.services) {
+ var list = $('<ul>');
+ for (var s in factory.services) {
+ list.append($('<li>').append(factory.services[s]));
+ }
+ _.find('td.Vservices').html(list);
+ } else { // Undefined
+ _.find('td.Vservices').html('<i>No provided service specifications</i>');
+ }
+
+ // Set the properties
+ $(tablePropBody).empty();
+ if (factory.properties) {
+ for (var s in factory.properties) {
+ var prop = factory.properties[s];
+ // For each properties clone the template
+ var entry = propEntryTemplate.clone().appendTo(tablePropBody).attr('id', 'property-' + prop.name);
+ entry.find('td.name').text(prop.name);
+ entry.find('td.type').text(prop.type);
+ entry.find('td.mandatory').text(prop.mandatory);
+ entry.find('td.immutable').text(prop.immutable);
+ if (prop.value) {
+ entry.find('td.value').text(prop.value);
+ } else {
+ entry.find('td.value').html('<i>No default value</i>');
+ }
+ }
+ } else {
+ // Hide the table
+ $('table.properties').hide();
+ }
+
+ // Set the required handlers.
+ if (factory.requiredHandlers) {
+ var list = $('<ul>');
+ for (var s in factory.requiredHandlers) {
+ list.append($('<li>').append(factory.requiredHandlers[s]));
+ }
+ _.find('td.VrequiredHandlers').html(list);
+ } else { // Undefined
+ _.find('td.VrequiredHandlers').html('<i>No required handlers</i>');
+ }
+
+ // Set the missing handlers.
+ if (factory.missingHandlers) {
+ var list = $('<ul>');
+ for (var s in factory.missingHandlers) {
+ list.append($('<li>').append(factory.missingHandlers[s]));
+ }
+ _.find('td.VmissingHandlers').html(list);
+ } else { // Undefined
+ _.find('td.VmissingHandlers').html('<i>No missing handlers</i>');
+ }
+
+ // Set the created instances.
+ if (factory.instances) {
+ var list = $('<ul>');
+ for (var s in factory.instances) {
+ var link = $('<a href=\'' + instances_url + '/' + factory.instances[s] +'\'>' + factory.instances[s] + '</a>');
+ list.append($('<li>').append(link));
+ }
+ _.find('td.VcreatedInstances').html(list);
+ } else { // Undefined
+ _.find('td.VcreatedInstances').html('<i>No created instances</i>');
+ }
+
+ _.find('pre.architecture_content').text(factory.architecture);
+}
+
+function retrieveDetails() {
+ $.get(pluginRoot + '/factories/' + factory_name + '.json', null, function(data) {
+ renderFactoryDetails(data);
+ }, "json");
+}
+
+function loadFactoriesData() {
+ window.location = factories_url;
+}
+
+function loadInstancesData() {
+ window.location = instances_url;
+}
+
+function loadHandlersData() {
+ window.location = handlers_url;
+}
+
+var tableBody = false;
+var tablePropBody = false;
+var propEntryTemplate = false;
+
+$(document).ready(function(){
+ tableBody = $('#plugin_table tbody');
+
+ tablePropBody = $('.properties tbody');
+ propEntryTemplate = tablePropBody.find('tr').clone();
+
+ retrieveDetails();
+
+ $(".instancesButton").click(loadInstancesData);
+ $(".factoriesButton").click(loadFactoriesData);
+ $(".handlersButton").click(loadHandlersData);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if ( link && link.length == 1 ) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+
+});
+
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/handler.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/handler.js
new file mode 100644
index 0000000..6298146
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/handler.js
@@ -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.
+ */
+function renderHandlersData(handlers) {
+ $(".statline").html(getHandlersStatLine(handlers));
+ tableBody.empty();
+ for ( var idx in handlers.data ) {
+ handlersEntry( handlers.data[idx] );
+ }
+ $("#plugin_table").trigger("update");
+}
+
+function getHandlersStatLine(handlers) {
+ return handlers.count + " handlers in total, "
+ + handlers.valid_count + " valid handlers, "
+ + handlers.invalid_count + " invalid handlers.";
+}
+
+function handlersEntry(handler) {
+ var name = handler.name;
+ var state = handler.state;
+ var bundle = handler.bundle;
+ var type = handler.type;
+
+ console.log("Create entry : " + handler);
+
+ var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'handler-' + handler.name);
+
+ _.find('td.name').text(name);
+ _.find('td.type').text(type);
+ _.find('td.bundle').text(bundle);
+ _.find('td.state').text(state);
+ if (handler.missing) {
+ _.find('td.missing').html(handler.missing);
+ } else {
+ _.find('td.missing').html('<i>No missing handlers</i>');
+ }
+
+}
+
+
+function loadHandlersData() {
+ console.log("Load handlers data");
+ $.get(pluginRoot + "/handlers.json", null, function(data) {
+ renderHandlersData(data);
+ }, "json");
+}
+
+function loadInstancesData() {
+ window.location = instances_url;
+}
+
+function loadFactoriesData() {
+ window.location = factories_url;
+}
+
+var tableBody = false;
+var tableEntryTemplate = false;
+
+$(document).ready(function(){
+ tableBody = $('#plugin_table tbody');
+ tableEntryTemplate = tableBody.find('tr').clone();
+
+ loadHandlersData();
+
+ $(".instancesButton").click(loadInstancesData);
+ $(".factoriesButton").click(loadFactoriesData);
+ $(".handlersButton").click(loadHandlersData);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if ( link && link.length == 1 ) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+ $("#plugin_table").tablesorter({
+ sortList: [[1,0]],
+ textExtraction:extractMethod
+ });
+});
+
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js
new file mode 100644
index 0000000..9efacc4
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/instance_detail.js
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+function renderInstanceDetails(data) {
+ $(".statline").html(getInstancesStatLine(data));
+ createDetail( data.data );
+}
+
+function getInstancesStatLine(instances) {
+ return instances.count + " instances in total, "
+ + instances.valid_count + " valid instances, "
+ + instances.invalid_count + " invalid instances.";
+}
+
+function createDetail(instance) {
+ console.log("Create details");
+ var service = "No provided services"
+
+ var _ = tableBody;
+
+ // Set the name
+ _.find('td.Vname').html(instance.name);
+
+ // Set the state
+ _.find('td.Vstate').text(instance.state);
+
+ // Set the factory
+ _.find('td.Vfactory').html('<a href="' + factories_url + '/' + instance.factory + '">' + instance.factory + '</a>');
+
+ if (instance.services) {
+ $(tableServiceBody).empty();
+ for (var s in instance.services) {
+ var service = instance.services[s];
+ // For each service clone the template
+ var entry = serviceEntryTemplate.clone().appendTo(tableServiceBody).attr('id', 'service-' + service.specification);
+ entry.find('td.name').text(service.specification);
+ entry.find('td.state').text(service.state);
+
+ if (service.id) {
+ entry.find('td.id').text(service.id);
+ } else {
+ entry.find('td.id').html('<i>not registered</i>');
+ }
+
+ if (service.properties) {
+ var list = $('<ul>');
+ for (var x in service.properties) {
+ list.append($('<li>').append(service.properties[x].name + ' = ' + service.properties[x].value));
+ }
+ entry.find('td.properties').html(list);
+ } else {
+ entry.find('td.properties').html('<i>not properties</i>');
+ }
+ }
+ } else {
+ // Hide the table
+ $('services').hide();
+ _.find('td.Vservices').html("No provided services");
+ }
+
+ if (instance.req) {
+ $(tableReqBody).empty();
+ for (var s in instance.req) {
+ var service = instance.req[s];
+ console.dir(service);
+ // For each service clone the template
+ var entry = reqEntryTemplate.clone().appendTo(tableReqBody).attr('id', 'req-' + service.id);
+ entry.find('td.name').text(service.specification);
+ if (service.filter) {
+ entry.find('td.filter').text(service.filter);
+ } else {
+ entry.find('td.filter').html('<i>no filter</i>');
+ }
+
+ entry.find('td.state').text(service.state);
+
+ entry.find('td.policy').text(service.policy);
+ entry.find('td.optional').text(service.optional);
+ entry.find('td.aggregate').text(service.aggregate);
+
+
+ if (service.matching) {
+ var list = $('<ul>');
+ for (var x in service.matching) {
+ if (service.matching[x].instance) {
+ var text = service.matching[x].instance + ' [' + service.matching[x].id + ']';
+ var link = $('<a href=\'' + instances_url + '/' + service.matching[x].instance +'\'>' + text + '</a>');
+ list.append($('<li>').append(link));
+ } else {
+ list.append($('<li>').append(service.matching[x].id));
+ }
+ }
+ entry.find('td.matching').html(list);
+ } else {
+ entry.find('td.matching').html('<i>no matching services</i>');
+ }
+
+ if (service.used) {
+ var list = $('<ul>');
+ for (var x in service.used) {
+ if (service.used[x].instance) {
+ var text = service.used[x].instance + ' [' + service.used[x].id + ']';
+ var link = $('<a href=\'' + instances_url + '/' + service.used[x].instance +'\'>' + text + '</a>');
+ list.append($('<li>').append(link));
+ } else {
+ list.append($('<li>').append(service.used[x].id));
+ }
+ }
+ entry.find('td.used').html(list);
+ } else {
+ entry.find('td.used').html('<i>no used services</i>');
+ }
+
+ }
+ } else {
+ // Hide the table
+ $('reqServices').hide();
+ _.find('td.VreqServices').html("No required services");
+ }
+
+
+ _.find('pre.architecture_content').text(instance.architecture);
+}
+
+function retrieveDetails() {
+ $.get(pluginRoot + '/instances/' + instance_name + '.json', null, function(data) {
+ renderInstanceDetails(data);
+ }, "json");
+}
+
+function loadFactoriesData() {
+ window.location = factories_url;
+}
+
+function loadInstancesData() {
+ window.location = instances_url;
+}
+
+function loadHandlersData() {
+ window.location = handlers_url;
+}
+
+var tableBody = false;
+var tableServiceBody = false;
+var serviceEntryTemplate = false;
+
+var tableReqBody = false;
+var reqEntryTemplate = false;
+
+
+$(document).ready(function(){
+ tableBody = $('#plugin_table tbody');
+
+ tableServiceBody = $('.services tbody');
+ serviceEntryTemplate = tableServiceBody.find('tr').clone();
+
+ tableReqBody = $('.reqServices tbody');
+ reqEntryTemplate = tableReqBody.find('tr').clone();
+
+
+ retrieveDetails();
+
+ $(".instancesButton").click(loadInstancesData);
+ $(".factoriesButton").click(loadFactoriesData);
+ $(".handlersButton").click(loadHandlersData);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if ( link && link.length == 1 ) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+
+});
+
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.css b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.css
new file mode 100644
index 0000000..33c5fbf
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+td.lheader {
+ width: 20em;
+ font-weight: bold;
+}
+
+div.architecture {
+ border-color: #CCC;
+ border-width: 1px;
+ border-style: solid;
+ border-spacing: 5px;
+ font-family: Courier;
+ margin: 5px;
+ background: #CCC;
+ width: 80em;
+ overflow: auto;
+ padding: 8px;
+}
diff --git a/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js
new file mode 100644
index 0000000..30cc9e0
--- /dev/null
+++ b/ipojo/webconsole-plugin/src/main/resources/res/ui/ipojo.js
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+function renderInstancesData(instances) {
+ $(".statline").html(getInstancesStatLine(instances));
+ tableBody.empty();
+ for ( var idx in instances.data ) {
+ instancesEntry( instances.data[idx] );
+ }
+ $("#plugin_table").trigger("update");
+}
+
+function getInstancesStatLine(instances) {
+ return instances.count + " instances in total, "
+ + instances.valid_count + " valid instances, "
+ + instances.invalid_count + " invalid instances.";
+}
+
+function instancesEntry(instance) {
+ var name = instance.name;
+ var state = instance.state;
+ var factory = instance.factory;
+
+ var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'instance-' + instance.name);
+
+ _.find('td.name').html('<a href="' + instances_url + '/' + name + '">' + name + '</a>');
+ _.find('td.factory').html('<a href="' + factories_url + '/' + factory + '">' + factory + '</a>');;
+ _.find('td.state').text(state);
+}
+
+
+function loadInstancesData() {
+ $.get(pluginRoot + "/instances.json", null, function(data) {
+ renderInstancesData(data);
+ }, "json");
+}
+
+function loadFactoriesData() {
+ window.location = factories_url;
+}
+
+function loadHandlersData() {
+ window.location = handlers_url;
+}
+
+var tableBody = false;
+var tableEntryTemplate = false;
+
+$(document).ready(function(){
+ tableBody = $('#plugin_table tbody');
+ tableEntryTemplate = tableBody.find('tr').clone();
+
+ loadInstancesData();
+
+ $(".instancesButton").click(loadInstancesData);
+ $(".factoriesButton").click(loadFactoriesData);
+ $(".handlersButton").click(loadHandlersData);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if ( link && link.length == 1 ) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+ $("#plugin_table").tablesorter({
+ sortList: [[1,0]],
+ textExtraction:extractMethod
+ });
+});
+